diff --git a/Euler.hs b/Euler.hs index 9b93e0f..8d9f97e 100644 --- a/Euler.hs +++ b/Euler.hs @@ -12,17 +12,19 @@ module Euler , primes , zipArraysWith , RangeIx(..) - , digitsOf , divisors , properDivisors , toDecimal , fromDecimal + , toDigits + , fromDigits , module Control.Applicative , module Control.Arrow , module Control.Monad , module Data.Function , module Data.List , module Data.Ratio + , module Data.Tuple , module Data.Word ) where @@ -36,6 +38,7 @@ import Data.Array.Unboxed import Data.Function import Data.List import Data.Ratio +import Data.Tuple import Data.Word import qualified Control.Monad.ST.Lazy as LST @@ -77,9 +80,6 @@ zipArraysWith :: (IArray arrA a, IArray arrB b, IArray arrC c, RangeIx i) zipArraysWith f as bs = array newRange $ [ (i, f (as!i) (bs!i)) | i <- range newRange ] where newRange = intersectBounds (bounds as) (bounds bs) -digitsOf :: (Read a, Show a, Integral a) => a -> [a] -digitsOf = map (read . (:[])) . show - divisors :: Integral a => a -> [a] divisors n = nub $ concat [ [m, q] | m <- takeWhile (\x -> x^2 <= n) [1..], let (q, r) = n `divMod` m, r == 0 ] @@ -105,7 +105,6 @@ toDecimal' n m = first (map fst) $ second (map fst) $ collect [] xs fromDecimal :: Decimal -> Rational fromDecimal (Decimal n ps rs) = (n % 1) + (p + r) * (1 % 10 ^ length ps) where (p, r) = (fromDigits ps % 1, fromDigits rs % (10 ^ length rs - 1)) - fromDigits = foldl' (\s d -> 10 * s + fromIntegral d) 0 deriving instance Eq Decimal deriving instance Ord Decimal @@ -116,3 +115,10 @@ instance Show Decimal where | null rs = show n ++ "." ++ concat (map show ps) | otherwise = show n ++ "." ++ concat (map show ps) ++ "(" ++ concat (map show rs) ++ ")" + +toDigits :: (Integral a, Integral b) => a -> [b] +toDigits = reverse . unfoldr (\x -> + if x == 0 then Nothing else Just (first fromIntegral $ swap (x `divMod` 10))) + +fromDigits :: (Integral a, Integral b) => [a] -> b +fromDigits = foldl' (\a b -> 10 * a + fromIntegral b) 0 diff --git a/Problem020.hs b/Problem020.hs index b1cad21..126b228 100644 --- a/Problem020.hs +++ b/Problem020.hs @@ -1,2 +1,2 @@ import Euler -main = print $ sum $ digitsOf $ product [1..100] +main = print $ sum $ toDigits $ product [1..100] diff --git a/Problem028.hs b/Problem028.hs new file mode 100644 index 0000000..58a2d6e --- /dev/null +++ b/Problem028.hs @@ -0,0 +1,23 @@ +-- Starting with the number 1 and moving to the right in a clockwise direction +-- a 5 by 5 spiral is formed as follows: +-- +-- 21 22 23 24 25 +-- 20 7 8 9 10 +-- 19 6 1 2 11 +-- 18 5 4 3 12 +-- 17 16 15 14 13 +-- +-- It can be verified that the sum of the numbers on the diagonals is 101. +-- +-- What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral +-- formed in the same way? + +ne = 1 : zipWith (+) nw [2,4..] +se = zipWith (+) ne [2,4..] +sw = zipWith (+) se [2,4..] +nw = zipWith (+) sw [2,4..] + +-- Sum of diagonals of an m by m spiral; m = 2*n + 1. +diagSum n = sum (take (n+1) ne ++ take n se ++ take n sw ++ take n nw) + +main = print $ (diagSum 2, diagSum 500) diff --git a/Problem029.hs b/Problem029.hs new file mode 100644 index 0000000..af8e793 --- /dev/null +++ b/Problem029.hs @@ -0,0 +1,4 @@ +-- How many distinct terms are in the sequence generated by a^b +-- for 2 ≤ a ≤ 100 and 2 ≤ b ≤ 100? +import Euler +main = print $ length $ nub [ a^b | a <- [2..100], b <- [2..100] ] diff --git a/Problem030.hs b/Problem030.hs new file mode 100644 index 0000000..0c88b9f --- /dev/null +++ b/Problem030.hs @@ -0,0 +1,4 @@ +-- Find the sum of all the numbers that can be written as the sum of fifth +-- powers of their digits. +import Euler +main = print $ sum $ filter (\n -> sum (map (^5) (toDigits n)) == n) [2..(6 * 9^5)] diff --git a/Problem031.hs b/Problem031.hs new file mode 100644 index 0000000..1d11ccd --- /dev/null +++ b/Problem031.hs @@ -0,0 +1,19 @@ +-- In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation: +-- +-- 1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p) +-- +-- How many different ways can £2 be made using any number of coins? + +import Data.Array +import Euler + +coins = listArray (0,7) [1,2,5,10,20,50,100,200] :: Array Int Int + +nWays total = arr ! (total, snd (bounds coins)) + where + arr = array ((0, fst (bounds coins)), (total, snd (bounds coins))) + [ ((n, c), sum [ arr ! (n - (coins!c'), c') + if n == coins!c' then 1 else 0 + | c' <- [fst (bounds coins)..c], coins!c' <= n ]) + | n <- [0..total], c <- indices coins ] + +main = print $ nWays 200 diff --git a/Problem032.hs b/Problem032.hs new file mode 100644 index 0000000..b7e5537 --- /dev/null +++ b/Problem032.hs @@ -0,0 +1,35 @@ +-- We shall say that an n-digit number is pandigital if it makes use of all the +-- digits 1 to n exactly once; for example, the 5-digit number, 15234, is 1 +-- through 5 pandigital. +-- +-- The product 7254 is unusual, as the identity, 39 × 186 = 7254, containing +-- multiplicand, multiplier, and product is 1 through 9 pandigital. +-- +-- Find the sum of all products whose multiplicand/multiplier/product identity +-- can be written as a 1 through 9 pandigital. +-- +-- HINT: Some products can be obtained in more than one way so be sure to only +-- include it once in your sum. + +import Euler + +partitions [] = [([],[])] +partitions (x:xs) = map (first (x:)) ps ++ map (second (x:)) ps + where ps = partitions xs + +main = print $ sum $ nub $ do + (as, as') <- partitions [1..9] + guard $ not $ null as + (bs, cs) <- partitions as' + guard $ not $ null bs + guard $ not $ null cs + guard $ length as <= length bs + guard $ length as <= length cs + guard $ length bs <= length cs + guard $ length as + length bs >= length cs + x <- fromDigits <$> permutations as + y <- fromDigits <$> permutations bs + guard $ x < y + let p = x * y + guard $ sort (toDigits p) == cs + return p