Life Goes On

まあまあだけど楽しんでる方です

23問目

http://projecteuler.net/index.php?section=problems&id=23
約数の和が元の数より大きいものを過剰数と呼ぶ。28123より大きい数は必ず二つの過剰数の和として表現できるが、二つの過剰数の和として表現できない全ての数の和を求める。
問題自体はそれほど難しくないのですが、これまでで最も実行時間がかかっています。(コンパイル済みのコードで数十秒)
何をどうしたら高速化できるんだろう?
ここで教えていただき、改善しました。
この問題は何度も見直してますが、単純に速さを求めるなら、Euler problems/Problem 23 - HaskellWiki のようにArrayモジュールを使うのが正解だと思います。

import Data.List

main = print $ euler023 28123

euler023 :: Int -> Int
euler023 limit = sum $ filter (not . isSumOfAbundants) [1..limit]

isSumOfAbundants :: Int -> Bool
isSumOfAbundants n = any test $ takeWhile (<= div n 2) abundants
  where abundants = filter isAbundant [1..]
        test a = isAbundant (n - a)

isAbundant :: Int -> Bool
isAbundant n = n < (sum $ divisors n)

divisors :: Int -> [Int]
divisors n = nub $ [1] ++ halfDivisors ++ (map (div n) halfDivisors)
  where halfDivisors = filter ((== 0) . mod n) [2..root]
        root = truncate $ sqrt $ fromIntegral n