1から順に時計回りに数字を並べて5×5の渦巻きを作ると以下のようになる(図 省略)。
このとき両方の対角線上の値の合計は101になる。
同じように1001×1001の渦巻きを作ったときに両方の対角線上にくる数の和を求 めよ。
実際に数字を並べて解くことも考えられるが、1001×1001というサイズや渦巻き 状に並べる処理なども大変そうなので、ここでは数学的な法則で求めることに する。問題ページの例を見ると一番中心は1、その周りは3,5,7,9と差が2の等差 数列、その周りは13,17,21,25と差が4の等差数列となっていることがわかる。 大きさnの渦巻きの場合、中心と、中心を除いた部分の半分の回数の4つの対角 線上の点の値の合計を求めればよいことがわかる。
まずは2,2,2,2,4,4,4,4,6,6,6,6…という差分diffsを定義する。ここでは repeatを用いて2の無限リストを生成し、それと自分自身を4つずらして zipWithで足しあわせることで生成している。次に1からその差分を使った数列 を生成する。scanl関数は与えられた関数と初期値にリストの値を順番に適用す る関数で、ここでは初期値1に+を適用することで、その差分を用いた数列を生 成している。この数列を前から(1001-1)/2周x4頂点+中心分の長さで取り出し和 を求める。
euler028 = sum $ take (((1001 - 1) `div` 2) * 4 + 1) $ scanl (+) 1 diffs
where diffs = zipWith (+) (repeat 2) (0:0:0:0:diffs)
