Problem 88
http://projecteuler.net/index.php?section=problems&id=88
調べる範囲が2~12000なので、product-sumの値は高々20000だとした。実際そうだった。
あまり速くない。やはり、Arrayはあまり速くないのか?
import Data.List import qualified Data.Set as S import Data.Maybe import Control.Arrow import Data.Array.IArray factors = factors' [2..] factors' (x:xs) n | n < x*x = [[n]] | mod n x == 0 = (map (x:).factors' (x:xs))(div n x) ++ factors' xs n | mod n x /= 0 = factors' xs n proSumToK n = map ((uncurry (+)).(first((-)n)).f).factors$n where f qs = (sum qs,genericLength qs) proSum a k = findIndex f$[0..] where f n = S.member k .(a!)$n proSums a k = S.toList.S.fromList.catMaybes.map (proSum a)$ [2..k] proSumToKArray :: Integer -> Array Integer (S.Set Integer) proSumToKArray m = listArray(0,m)$map (S.fromList.proSumToK)$[0..m] main =print.sum.proSums (proSumToKArray 20000)$12000
Setを使ってみた。
import Data.List import qualified Data.Set as S factors = factors' [2..] factors' (x:xs) n | n < x*x = [[n]] | mod n x == 0 = (map (x:).factors' (x:xs))(div n x) ++ factors' xs n | mod n x /= 0 = factors' xs n proSumToK n = map (\ x->n-sum x+genericLength x).factors$n update k (s,ns,n) = foldl insert' (s,ns,n+1) .filter need .proSumToK $n where need x = 1<=x && x<=k && S.notMember x s insert'(t,ms,m) k = (S.insert k t,add n ms,m) add x (y:ys) | x==y = y:ys | x/=y = x:y:ys p088 k = sum.second.until allIn (update k)$(S.empty,[0],0) where first (a,b,c) = a second (a,b,c) = b allIn =(==k).S.size.first main = print.p088$12000
イメージとしてはproduct-sum=n (0,1,2..) でできるkをどんどんSetに突っ込んでSetにほしいものが全部入ったら終了。
サーチが1つ減ったので、結構速くなった。