Problem 245
コンテンツ
245 Coresilience
オイラーのφ関数がらみの問題.
c(n) = (n – φ(n)) / (n – 1) = 1 / k となるような,合成数の和を求める.
探索範囲が 2 <= n <= 10^11 と広いが…
結論から言うと,全探索.
重要な点はどのように,探索範囲を狭くするか.
次のことが分かる(これぐらいしか分からなかった):
- n は奇数,
- n は同じ素因数を2以上含まない,
- k は n の最小素因数以下で偶数.
やったことは,n = p * q であるか,ないかで場合分け.
n = p * q のときはpを固定して,ある値の約数を列挙して,qを探した.
そうでないときは,最大の素因数を k を loop して,探した.
import Number (primes, isPrime, divisors) import Data.List (findIndex) import Control.Monad (guard) main :: IO () main = print.sum.p245 $ 10^11 search :: Integer -> [Integer] -> [Integer] search u [p] = do d <- takeWhile (<= div u p + p - 1).dropWhile (< 2 * p + 1).divisors $ p^2 - p + 1 let q = d - p + 1 guard $ isPrime q return $ p * q search u ps = do k <- filter even [kL..minimum [kU1, kU2, p1 - 1]] let (p, r) = divMod (k * f + 1) (m - k * (m - f)) guard $ r == && isPrime p return $ m * p where m = product ps f = product.map pred $ ps (p1, p2) = (head ps, last ps) kL = div (m * p2 - 1) ((m - f) * p2 + f) + 1 kU1 = div m (m - f) kU2 = div (m * (u - 1)) (m * f + u * (m - f)) candidates :: Integer -> Integer -> Integer -> [[Integer]] candidates 1 _ _ = [[]] candidates a l u = concat [map (p:).candidates (a-1) p $ div u p | p <- takeWhile (<=u').dropWhile (<=l) $ primes] where u' = floor.(** (1 / (fromInteger a))).fromInteger $ u solutions :: Integer -> Integer -> [Integer] solutions u a = concatMap (search u).candidates a 2 $ u p245 :: Integer -> [Integer] p245 u = map (sum.solutions u) $ [2..toInteger $ aU + 1] where Just aU = findIndex (>u).scanl (*) 1.tail $ primes
実行時間は1分切っているが,どうもマシンパワーに頼っているという,感じがしてならない.
(Core 2 Duo 3.16GHz)
まいどのことだが,どうせ C++ で実装したら100倍ぐらい速くなるんだって.多分.
作成者 Toru Mano
最終更新時刻 2023-01-01 (c70d5a1)