Project Euler 38,39

Problem 38

http://projecteuler.net/index.php?section=problems&id=38


nで分ける。そのとき左辺第一項をmとして、mの範囲が決まる。例えば、n=4なら、右辺は最初の2つは3桁で残りは2桁だから、

2m ≥ 100, 3m < 100 => 34 ≤ m ≤ 50

range n = if k < n then [div (10^m + k) (k + 1) .. div (10^m - 1) k]
                   else [10^(m-1) .. div (10^m - 1) n]
                where
                    m = div 9 n
                    k = n * (m + 1) - 9

digits 0 = []
digits n = (digits (div n 10)) ++ [mod n 10]
is_pan a = (foldr (\x y -> y + 2^x) 0 a) == 2^10 - 2
numerize a = foldl (\x y -> x * 10 + y) 0 a

a = concat [ [ [ m * k | k <- [1..n] ] | m <- range n ] | n <- [2..9] ]
b = filter is_pan (map (\e -> concat (map digits e)) a)
main = print(foldr max 0 (map numerize b))

Problem 39

http://projecteuler.net/index.php?section=problems&id=39


ピタゴラス数の生成公式を使う。素因数分解すれば簡単に個数が分かる。

import Data.Array

sieve f p | f!p == 1  = sieve (f // [ (m, p) | m <- a, f!m == 1 ]) (p + 1)
          | p * p > n = f
          | otherwise  = sieve f (p + 1)
                where a = if p == 2 then [p*2,p*3..n] else [p*3,p*5..n]

n = 1000
f = sieve (array (2, n) [ (k, 1) | k <- [2..n] ]) 2

div_pow n p | mod n p /= 0 = (n, 0)
            | otherwise    = (\(n, e) -> (n, e + 1)) (div_pow (div n p) p)

factorize 1 = []
factorize n | f!n == 1  = [ (n, 1) ]
            | otherwise = [(p, e)] ++ (factorize m)
                where
                    p = f!n
                    (m, e) = div_pow n (f!n)

divs [] = [1]
divs ((p,e):fs) = [ p^e1 * n | e1 <- [0..e], n <- (divs fs) ]
d = divs . factorize

d3 m = concat (map (\(p,r) -> [ (p,q,div r q) | q <- d r ])
                                (map (\p -> (p, div m p)) (d m)))
is_valid_triplet (_,m,n) = 
        (mod n 2) == 1 && m < n && n < m * 2 && gcd m n == 1
count_Pythagoras m = length (filter is_valid_triplet (d3 (div m 2)))
greater x y = if snd x >= snd y then x else y
a = foldl1 greater [ (k, count_Pythagoras k) | k <- [2,4..n] ]
main = print(fst a)