Project Euler – 問題19

以下のような情報が与えられている。さらに自分自身で調べてもよい。

1900年1月1日は月曜である
9月4月6月11月は30日である
それ以外の月は31日である
ただし2月は28日である
うるう年の場合は29日である
4で割り切れる年がうるう年であるが、 世紀の年は400で割り切れなければうるう年ではない

20世紀の間で月の初めが日曜日であった回数を求めよ。

Zellerの公式というものを使うと年・月・日から曜日を計算できるらしい。そ の式をHaskellで記述したものが以下のzeller関数である。月が1または2の時は 前年の13または14として計算する。以下の式を計算した値が0のときが日曜日で ある。そこで20世紀の全ての月の最初の日の曜日のリストを生成し、その中で 値が0であるものの数を数えると答えを求めることができる。

zeller y m d = if m < 3
               then zeller' (y - 1) (m + 12)
               else zeller' y m
    where zeller' y m = (y + y `div` 4 - y `div` 100 + y `div` 400
                         + (13 * m + 8) `div` 5 + d) `mod` 7

euler019 = length $ filter (== 0) [zeller y m 1
                                   | y <- [1901..2000], m <- [1..12]]