xs !! n
具有线性复杂度。您应该尝试使用对数或常量访问数据结构。
编辑:这是我通过 augustss 复制类似的一个快速实现:
psOpt x = psArr x
where psCall 0 = 1
psCall n = sum $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (psArr (n-pent))
psArr n = if n > ncache then psCall n else psCache ! n
psCache = listArray (0,ncache) $ map psCall [0..ncache]
在 ghci 中,我观察到您的列表版本没有明显的加速。没运气 !
编辑:
确实,-O2
正如 Chris Kuklewicz 所建议的那样,这个解决方案比你的 for 快八倍n=5000
。结合 Hammar 对 10^6 求和的见解,我得到了一个足够快的解决方案(在我的机器上大约 10 秒内找到希望正确的答案):
import Data.List (find)
import Data.Array
ps = 1 : map p [1..] where
p n = sum $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (ps !! (n-pent))
summod li = foldl (\a b -> (a + b) `mod` 10^6) 0 li
ps' = 1 : map p [1..] where
p n = summod $ map getP $ takeWhile ((<= n).fst) pents where
getP (pent,sign) = sign * (ps !! (n-pent))
ncache = 1000000
psCall 0 = 1
psCall n = summod $ map getP $ takeWhile ((<= n).fst) pents
where getP (pent,sign) = sign * (psArr (n-pent))
psArr n = if n > ncache then psCall n else psCache ! n
psCache = listArray (0,ncache) $ map psCall [0..ncache]
pents = zip (map (\n -> ((3*n-1)*n `div` 2) `mod` 10^6) $ [1..] >>= (\x -> [x,-x]))
(cycle [1,1,-1,-1])
(我破坏了 psCache 抽象,所以你应该使用psArr
而不是psOpt
; 这可以确保不同的调用psArr
将重用相同的记忆数组。这在你编写时很有用find ((== 0) . ...)
......好吧,我认为最好不要发布完整的解决方案。 )
感谢大家的额外建议。