Project Euler – 問題34

145は1!+4!+5!=1+24+120=145となる面白い数である。

各桁の数の階乗の和が自分自身と等しくなるような全ての数の和を求めよ。

注意:1!=1と2!=2は和ではないので含めない。

問題30と同様に9!*7が7桁なので3000000以上の数に解がないことがわかる。ま た1や2は和じゃないので含まないと問題の注釈にあるので、3から3000000の数 のリストについて条件を満たすかを試すことにする。

まずは階乗のリストをfactorialsとして無限リストで定義する。ここでは scanl関数を使用する。scanl関数は与えられた関数と初期値でリストの要素を 順番に適用していく。次の要素に適用するときは初期値の変わりに前の結果を 使うので、例えば掛け算では階乗のような値を求めることができる。結果のリ ストには初期値も含まれるので、以下の定義で0からの階乗のリストとなる。こ の場合!!の操作で階乗の値を取り出せるので直感的である。

次に自然数を各桁ごとの数のリストに変換する関数intToListを定義する。ここ では10より小さくなるまで10で割り、そのあまりをリストにして最後に reverseで順番を整えている。この問題では実際には順番は関係ない。

factorials = scanl (*) 1 [1..]

intToList n = reverse $ i' n
    where i' n
              | n >= 10   = let (d, m) = divMod n 10
                            in m : i' d
              | otherwise = [n]

euler034 = sum $ filter curious [3..3000000]
    where curious n = (sum $ map (factorials !!) $ intToList n) == n