2011-10-26
Project Euler 49
問題はこちら。
これは個人的に素直にできたと思います。
でもネットを徘徊するとやたら複雑なコードなものが多くて、
はてにゃ?と思いました。なんで・・・。
まあ自分のコード、微妙に汎用性みたいなものないですが笑
import Data.List
--今回使う範囲の素数リスト
a :: [Integer]
a = takeWhile (<3340) $ dropWhile (<1000) primesList
--要素数3のリストが全部素数ならTrue。
f :: [Integer] -> Bool
f [x,y,z] = all isPrime [x,y,z]
--要素数3のリストの全要素ををshowしてsortして全て同じならTrue。
g :: [Integer] -> Bool
g [x,y,z] = (\[a,b,c] -> (a==b) && (b==c) && (c==a)) $ map (sort.show) [x,y,z]
--項差3300で項数3の数列のリストを作る。
h :: [Integer] -> [[Integer]]
h [] = []
h (x:xs) = [x,(x+3330),(x+6660)] : h xs
b :: [[Integer]]
b = h a
--要素数3のリストの要素を全てshowして連結させて数値に戻す。
i :: [Integer] -> Integer
i [x,y,z] = read (show x ++ show y ++ show z) :: Integer
--らすとおー。
main = print $ i $ last $ filter g (filter f b)
--素数の無限リスト。
primesList :: [Integer]
primesList = map fromIntegral primesList'
where
primesList' = [2, 3, 5] ++ f 5 7 (drop 2 primesList')
f m s (p : ps) = [n | n <- ns, gcd m n == 1] ++ f (m * p) (p * p) ps
where ns = [x + y | x <- [s, s + 6 .. p * p - 2], y <- [0, 4]]
--素数判定。
isPrime :: Integer -> Bool
isPrime n = (n > 1) && isPrime' primesList
where
isPrime' (x : xs)
| x * x > n = True
| rem n x == 0 = False
| otherwise = isPrime' xs
Project Euler 46
問題はこちら。
微妙にハマりました。
アプローチを変えたらできたので、まずそちらを。
--奇合成数の無限リスト
a :: [Integer]
a = [ x | x <- [3,5..] , (not.isPrime) x]
--2乗して2かけた数の無限リスト
b :: [Integer]
b = map (\n -> 2*n^2) [1..]
--ちょめちょめする。内包表記の中で内包表記を使ってうんちゃらと。
main = print $ head $ [ x | x <- a , all (not.isPrime) $ takeWhile (>0) [ x-y | y <- b ] ]
--素数の無限リスト。
primesList :: [Integer]
primesList = map fromIntegral primesList'
where
primesList' = [2, 3, 5] ++ f 5 7 (drop 2 primesList')
f m s (p : ps) = [n | n <- ns, gcd m n == 1] ++ f (m * p) (p * p) ps
where ns = [x + y | x <- [s, s + 6 .. p * p - 2], y <- [0, 4]]
--素数判定。
isPrime :: Integer -> Bool
isPrime n = (n > 1) && isPrime' primesList
where
isPrime' (x : xs)
| x * x > n = True
| rem n x == 0 = False
| otherwise = isPrime' xs
で、ハマったのが以下。未だによく解らない。
最後の行がprimesListになった途端だめになる。
他の普通のリストとかだと大丈夫なのになんで…。
--二乗数か判定するよ。 f :: (Floating a) => a -> Bool f n = a !! ((length a)-2) == '.' && last a == '0' where a = show (sqrt n) --なんだかんだでこんな感じにやる。 g n (x:xs) | n < x = False | f ((n-x)/2) = True | otherwise = g n xs h n = g n primesList
混乱してきたのでまた今度。
Project Euler 45
問題はこちら。
これは結構簡単でした。
五角数と六角数だけでやれば良いので、
単純に同じものがあるかどうか調べました。
--まずは五角数、六角数の無限リストを作る。 p :: [Integer] p = dropWhile (<= 40755) $ map (\n -> div (n*(3*n-1)) 2) [1..] h :: [Integer] h = dropWhile (<= 40755) $ map (\n -> n*(2*n-1)) [1..] --地道にあるかどうか調べる。 f :: [Integer] -> [Integer] -> Integer f (x:xs) (y:ys) | elem x (takeWhile (<=x) (y:ys)) = x | otherwise = f xs (dropWhile (<=x) (y:ys)) --もうおわり。 main = print $ f p h
Project Euler 43
問題はこちら。
結構死んだけどできたわあい!
でも余裕は全然ないので、解説というより完全に自分用メモです。
すいませんorz
import Data.List
--bはaで割り切れるか。
f :: Int -> Int -> Bool
f a b = mod b a == 0
--[[17で割り切れる3桁の数リスト],[11で割り切れる3桁の数リスト]・・・]を作る。
g :: [Int] -> [Int] -> [[Int]]
g _ [] = []
g xs (y:ys) = filter (f y) xs : g xs ys
--ちょっとmapのmapに注意。
a :: [[String]]
a = map (map (show)) $ g [12..987] [17,13,11,7,5,3,2]
--2ケタは先頭に0つけないとだめだあー!
zero :: String -> String
zero c
| length c == 2 = "0" ++ c
| otherwise = c
--というわけでaの完成版b。
b :: [[String]]
b = map (map (zero)) a
--リストの要素が全て違うならTrue。
diff xs
| (length ss == 1) = True
| (head ss == ss !! 1) = False
| otherwise = diff (tail ss)
where ss = sort xs
--h [17で割り切れる3桁の数リスト] [11で割り切れる3桁の数リスト] みたいにしてちょめちょめ。
h :: [String] -> [String] -> [String]
h xs ys = [ [head y] ++ x | x <- xs , y <- ys ,
(tail y == take 2 x) && (diff $ ([head y] ++ x)) ]
--scanl1でさっき作ったbのリストにhを順々に適用(これで出るのかあ)。
c :: [String]
c = last $ scanl1 h b
--最後に足りない数字を見つけて先頭に足す(忘れてた)。
j' :: String -> String -> String
j' (x:xs) (y:ys)
| (x == y) = j' xs ys
| otherwise = [y]
j :: String -> String
j k = j' (sort k) "0123456789" ++ k
--これが最終的に欲しいリスト。
d :: [String]
d = map j c
--さいごなのっ!
main = print $ sum $ map (\n -> read n :: Integer) d
ほんと、これは自分としては結構ハマった問題でした(トホホ。
