Personal tools

Euler problems/121 to 130

From HaskellWiki

< Euler problems(Difference between revisions)
Jump to: navigation, search
m
 
(8 intermediate revisions by 4 users not shown)
Line 1: Line 1:
== [http://projecteuler.net/index.php?section=view&id=121 Problem 121] ==
+
== [http://projecteuler.net/index.php?section=problems&id=121 Problem 121] ==
 
Investigate the game of chance involving coloured discs.
 
Investigate the game of chance involving coloured discs.
  
Line 18: Line 18:
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=122 Problem 122] ==
+
== [http://projecteuler.net/index.php?section=problems&id=122 Problem 122] ==
 
Finding the most efficient exponentiation method.
 
Finding the most efficient exponentiation method.
  
Line 46: Line 46:
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=123 Problem 123] ==
+
== [http://projecteuler.net/index.php?section=problems&id=123 Problem 123] ==
 
Determining the remainder when (pn − 1)n + (pn + 1)n is divided by pn2.
 
Determining the remainder when (pn − 1)n + (pn + 1)n is divided by pn2.
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]
 
 
primeFactors n = factor n primes
 
    where
 
        factor _ [] = []
 
        factor m (p:ps) | p*p > m        = [m]
 
                        | m `mod` p == 0 = p : [m `div` p]
 
                        | otherwise      = factor m ps
 
 
isPrime :: Integer -> Bool
 
isPrime 1 = False
 
isPrime n = case (primeFactors n) of
 
                (_:_:_)  -> False
 
                _        -> True
 
 
 
problem_123 =  
 
problem_123 =  
     head[a+1|a<-[20000,20002..22000],
+
     fst . head . dropWhile (\(n,p) -> (2 + 2*n*p) < 10^10) $
    let n=2*(a+1)*primes!!(fromInteger a),
+
     zip [1..] primes
    n>10^10
+
     ]
+
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=124 Problem 124] ==
+
== [http://projecteuler.net/index.php?section=problems&id=124 Problem 124] ==
 
Determining the kth element of the sorted radical function.
 
Determining the kth element of the sorted radical function.
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
import List
+
import Data.List
primes :: [Integer]
+
import Data.Ord (comparing)
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]
+
 
+
compress = map head . group
primeFactors :: Integer -> [Integer]
+
 
primeFactors n = factor n primes
+
rad = product . compress . primeFactors
    where
+
        factor _ [] = []
+
        factor m (p:ps) | p*p > m        = [m]
+
                        | m `mod` p == 0 = p : factor (m `div` p) (p:ps)
+
                        | otherwise      = factor m ps
+
problem_124=snd$(!!9999)$sort[(product$nub$primeFactors x,x)|x<-[1..100000]]
+
  
 +
radfax = (1,1) : zip [2..] (map rad [2..])
 +
 +
sortRadfax n = sortBy (comparing snd) $ take n radfax
 +
problem_124=fst$sortRadfax 100000!!9999
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=125 Problem 125] ==
+
== [http://projecteuler.net/index.php?section=problems&id=125 Problem 125] ==
 
Finding square sums that are palindromic.
 
Finding square sums that are palindromic.
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
import Data.List  
+
import Data.List as L
import Data.Map(fromList,(!))
+
import Data.Set as S
 +
 +
hi = 100000000
 +
 +
ispalindrome n = (show n) == reverse (show n)
 +
 +
-- the "drop 2" ensures all sums use at least two terms
 +
-- by ignoring the 0- and 1-term "sums"
 +
sumsFrom i =
 +
    takeWhile (<hi) .
 +
    drop 2 .
 +
    scanl (\s n -> s + n^2) 0 $ [i..]
 +
 +
limit =
 +
    truncate . sqrt . fromIntegral $ (hi `div` 2)
  
toFloat = (flip encodeFloat 0)
+
problem_125 =
digits n
+
    fold (+) 0 .
{-  123->[3,2,1]
+
     fromList .
-}
+
     concat .
     |n<10=[n]
+
     L.map (L.filter ispalindrome . sumsFrom) $ [1 .. limit]
     |otherwise= y:digits x
+
</haskell>
    where
+
     (x,y)=divMod n 10
+
  
palind n=foldl dmm 0 (digits n)
+
== [http://projecteuler.net/index.php?section=problems&id=126 Problem 126] ==
-- 123 ->321
+
Exploring the number of cubes required to cover every visible face on a cuboid.
dmm=(\x y->x*10+y)
+
  
makepalind n=(n*d+p):[c+b*d|b<-[0..9]]
+
Solution:
    where
+
<haskell>
    a=(+1)$floor$logBase 10$fromInteger n
+
import Data.Array.ST
    d=10^a
+
import Control.Monad (when)
    p=palind n
+
import Control.Monad.ST
    c=n*10*d+p
+
  
twomakep n=(n*d+p)
+
limit = 20000
    where
+
layer x y z n = 4*(x+y+z+n-2)*(n-1) + 2*x*y + 2*x*z + 2*y*z
    a=(+1)$floor$logBase 10$fromInteger n
+
    d=10^a
+
    p=palind n
+
  
p125=sum[b|a<-[1..999], b<-makepalind a,not$null$ funa b]
+
solutions :: STUArray s Int Int -> Int -> ST s ()
p125a=sum[b|a<-[1000..9999], let b=twomakep a,not$null$ funa b]
+
solutions a n =
p125b=sum[a|a<-[1..9], not$null$ funa a]
+
    when (layer 1 1 1 n <= limit) $
 +
            do solutions a (n+1)
 +
                solutions' a 1 n
  
findmap=fromList[(a,2*fill_map a)|a<-[0..737]]
+
solutions' :: STUArray s Int Int -> Int -> Int -> ST s ()
fill_map x
+
solutions' a x n =
    |odd x=fastsum $div (x-1) 2
+
     when (layer x x x n <= limit) $
     |otherwise=fastsumodd (x-1)
+
            do solutions' a (x+1) n
    where
+
                solutions'' a x x n
    fastsum  y=div (y*(y+1)*(2*y+1)) 6
+
    fastsumodd  y=let n=div (y+1) 2 in div (n*(4*n*n-1)) 3
+
  
funa x=[(a,x)|a<-takeWhile (\a->a*a*a<4*x) [2..],funb a x]
+
solutions'' :: STUArray s Int Int -> Int -> Int -> Int -> ST s ()
funb x n
+
solutions'' a x y n =
    |odd x=d2==0 && 4*d1>=(x+1)^2 && isSq d1
+
     when (layer x y y n <= limit) $
     |otherwise=d4==0 && odd d3 && d3>=(x+1)^2 && isSq d3
+
            do solutions'' a x (y+1) n
    where
+
                solutions''' a x y y n
    x1=fromInteger x
+
    (d1,d2)=divMod ((n-findmap! x1)) (x)
+
    (d3,d4)=divMod ((4*n-findmap!x1)) (x)
+
isSq x=(floor$sqrt$toFloat x)^2==x
+
problem_125 = (p125+p125a+p125b)
+
</haskell>
+
  
== [http://projecteuler.net/index.php?section=view&id=126 Problem 126] ==
+
solutions''' :: STUArray s Int Int -> Int -> Int -> Int -> Int -> ST s ()
Exploring the number of cubes required to cover every visible face on a cuboid.
+
solutions''' a x y z n =
 +
    when (layer x y z n <= limit) $
 +
            do readArray a (layer x y z n) >>= return.(+1) >>= writeArray a (layer x y z n)
 +
                solutions''' a x y (z+1) n
  
Solution:
+
findSolution :: STUArray s Int Int -> Int -> ST s (Maybe Int)
<haskell>
+
findSolution a n
problem_126 = undefined
+
    | n == limit = return Nothing
 +
    | otherwise = do
 +
        v <- readArray a n
 +
        if v == 1000
 +
            then return (Just n)
 +
            else findSolution a (n+1)
 +
 
 +
main :: IO ()
 +
main = print foo
 +
  where foo = runST $
 +
              do cn <- newArray (0,limit+1) 0 :: ST s (STUArray s Int Int)
 +
                solutions cn 1
 +
                findSolution cn 154
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=127 Problem 127] ==
+
== [http://projecteuler.net/index.php?section=problems&id=127 Problem 127] ==
 
Investigating the number of abc-hits below a given limit.
 
Investigating the number of abc-hits below a given limit.
  
Line 183: Line 180:
 
     rads = listArray (1,n) $ map rad [1..n]
 
     rads = listArray (1,n) $ map rad [1..n]
 
     invrads = sort $ map (\(a,b) -> (b, a)) $ assocs rads
 
     invrads = sort $ map (\(a,b) -> (b, a)) $ assocs rads
primeFactors :: Integer -> [Integer]
 
primeFactors n = factor n primes
 
    where
 
        factor _ [] = []
 
        factor m (p:ps) | p*p > m        = [m]
 
                        | m `mod` p == 0 = p : factor (m `div` p) (p:ps)
 
                        | otherwise      = factor m ps
 
merge xs@(x:xt) ys@(y:yt) = case compare x y of
 
    LT -> x : (merge xt ys)
 
    EQ -> x : (merge xt yt)
 
    GT -> y : (merge xs yt)
 
   
 
diff  xs@(x:xt) ys@(y:yt) = case compare x y of
 
    LT -> x : (diff xt ys)
 
    EQ -> diff xt yt
 
    GT -> diff xs yt
 
 
primes, nonprimes :: [Integer]
 
primes    = [2,3,5] ++ (diff [7,9..] nonprimes)
 
nonprimes = foldr1 f . map g $ tail primes
 
    where f (x:xt) ys = x : (merge xt ys)
 
          g p = [ n*p | n <- [p,p+2..]]
 
 
problem_127 = main
 
problem_127 = main
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=128 Problem 128] ==
+
== [http://projecteuler.net/index.php?section=problems&id=128 Problem 128] ==
 
Which tiles in the hexagonal arrangement have prime differences with neighbours?
 
Which tiles in the hexagonal arrangement have prime differences with neighbours?
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
problem_128 = undefined
+
p128=
 +
    concat[m|a<-[0..70000],let m=middle a++right a,not$null m]
 +
    where
 +
    middle n
 +
        |all isPrime [11+6*n,13+6*n,29+12*n]=[2+3*(n+1)*(n+2)]
 +
        |otherwise=[]
 +
    right n
 +
        |all isPrime [11+6*n,17+6*n,17+12*n]=[1+3*(n+2)*(n+3)]
 +
        |otherwise=[]
 +
problem_128=do
 +
    print(p128!!1997)
 +
isPrime x
 +
    |x<100=isPrime' x
 +
    |otherwise=all (millerRabinPrimality x )[2,7,61]
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=129 Problem 129] ==
+
== [http://projecteuler.net/index.php?section=problems&id=129 Problem 129] ==
 
Investigating minimal repunits that divide by n.
 
Investigating minimal repunits that divide by n.
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
problem_129 = undefined
+
import Data.List
 +
factors x=fac$fstfac x
 +
funp (p,1)=
 +
    head[a|
 +
    a<-sort$factors (p-1),
 +
    powMod p 10 a==1
 +
    ]
 +
funp (p,s)=p^(s-1)*funp (p,1)
 +
funn []=1
 +
funn (x:xs) =lcm (funp x) (funn xs)
 +
p129 q=
 +
    head[a|
 +
    a<-[q..],
 +
    gcd a 10==1,
 +
    let s=funn$fstfac$(*9) a,
 +
    s>q,
 +
    s>a
 +
    ]
 +
problem_129 = p129 (10^6)
 
</haskell>
 
</haskell>
  
== [http://projecteuler.net/index.php?section=view&id=130 Problem 130] ==
+
== [http://projecteuler.net/index.php?section=problems&id=130 Problem 130] ==
 
Finding composite values, n, for which n−1 is divisible by the length of the smallest repunits that divide it.
 
Finding composite values, n, for which n−1 is divisible by the length of the smallest repunits that divide it.
  
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
import Data.List
+
--factors powMod in p129
mulMod :: Integral a => a -> a -> a -> a
+
fun x  
mulMod a b c= (b * c) `rem` a
+
     |(not$null a)=head a  
squareMod :: Integral a => a -> a -> a
+
squareMod a b = (b * b) `rem` a
+
pow' :: (Num a, Integral b) => (a -> a -> a) -> (a -> a) -> a -> b -> a
+
pow' _ _ _ 0 = 1
+
pow' mul sq x' n' = f x' n' 1
+
     where
+
    f x n y
+
        | n == 1 = x `mul` y
+
        | r == 0 = f x2 q y
+
        | otherwise = f x2 q (x `mul` y)
+
        where
+
            (q,r) = quotRem n 2
+
            x2 = sq x
+
powMod :: Integral a => a -> a -> a -> a
+
powMod m = pow' (mulMod m) (squareMod m)
+
+
primeFactors :: Integer -> [Integer]
+
primeFactors n = factor n primes
+
    where
+
        factor _ [] = []
+
        factor m (p:ps) | p*p > m        = [m]
+
                        | m `mod` p == 0 = p : factor (m `div` p) (p:ps)
+
                        | otherwise      = factor m ps
+
+
primes=2:[a|a<-[2..],isPrime a]
+
isPrime :: Integer -> Bool
+
isPrime 1 = False
+
isPrime n = case (primeFactors n) of
+
                (_:_:_)  -> False
+
                _        -> True
+
fstfac x = [(head a ,length a)|a<-group$primeFactors x]
+
fac [(x,y)]=[x^a|a<-[0..y]]
+
fac (x:xs)=[a*b|a<-fac [x],b<-fac xs]
+
factors x=fac$fstfac x
+
fun x |(not$null a)=head a  
+
 
     |otherwise=0
 
     |otherwise=0
 
     where  
 
     where  

Latest revision as of 18:29, 21 February 2010

Contents

[edit] 1 Problem 121

Investigate the game of chance involving coloured discs.

Solution:

import Data.List
problem_121 = possibleGames `div` winningGames
   where
   possibleGames = product [1..16]
   winningGames = 
       (1+) $ sum $ map product $ chooseUpTo 7 [1..15]
   chooseUpTo 0     _ = []
   chooseUpTo (n+1) x = 
       [y:z | 
       (y:ys) <- tails x,
       z <- []: chooseUpTo n ys
       ]

[edit] 2 Problem 122

Finding the most efficient exponentiation method.

Solution using a depth first search, pretty fast :

import Data.List
import Data.Array.Diff
import Control.Monad
 
depthAddChain 12 branch mins = mins
depthAddChain d branch mins = foldl' step mins $ nub $ filter (> head branch)
                               $ liftM2 (+) branch branch
    where
      step da e | e > 200 = da
                | otherwise =
                    case compare (da ! e) d of
                      GT -> depthAddChain (d+1) (e:branch) $ da // [(e,d)]
                      EQ -> depthAddChain (d+1) (e:branch) da
                      LT -> da
 
baseBranch = [2,1]
 
baseMins :: DiffUArray Int Int
baseMins = listArray (1,200) $ 0:1: repeat maxBound
 
problem_122 = sum . elems $ depthAddChain 2 baseBranch baseMins

[edit] 3 Problem 123

Determining the remainder when (pn − 1)n + (pn + 1)n is divided by pn2.

Solution:

problem_123 = 
    fst . head . dropWhile (\(n,p) -> (2 + 2*n*p) < 10^10) $
    zip [1..] primes

[edit] 4 Problem 124

Determining the kth element of the sorted radical function.

Solution:

import Data.List
import Data.Ord (comparing)
 
compress = map head . group
 
rad = product . compress . primeFactors
 
radfax = (1,1) : zip [2..] (map rad [2..])
 
sortRadfax n = sortBy (comparing snd) $ take n radfax
problem_124=fst$sortRadfax 100000!!9999

[edit] 5 Problem 125

Finding square sums that are palindromic.

Solution:

import Data.List as L
import Data.Set as S
 
hi = 100000000
 
ispalindrome n = (show n) == reverse (show n)
 
-- the "drop 2" ensures all sums use at least two terms
-- by ignoring the 0- and 1-term "sums"
sumsFrom i =
    takeWhile (<hi) .
    drop 2 .
    scanl (\s n -> s + n^2) 0 $ [i..]
 
limit =
    truncate . sqrt . fromIntegral $ (hi `div` 2)
 
problem_125 =
    fold (+) 0 .
    fromList .
    concat .
    L.map (L.filter ispalindrome . sumsFrom) $ [1 .. limit]

[edit] 6 Problem 126

Exploring the number of cubes required to cover every visible face on a cuboid.

Solution:

import Data.Array.ST
import Control.Monad (when)
import Control.Monad.ST
 
limit = 20000
layer x y z n = 4*(x+y+z+n-2)*(n-1) + 2*x*y + 2*x*z + 2*y*z
 
solutions :: STUArray s Int Int -> Int -> ST s ()
solutions a n =
    when (layer 1 1 1 n <= limit) $
             do solutions a (n+1)
                solutions' a 1 n
 
solutions' :: STUArray s Int Int -> Int -> Int -> ST s ()
solutions' a x n =
    when (layer x x x n <= limit) $
             do solutions' a (x+1) n
                solutions'' a x x n
 
solutions'' :: STUArray s Int Int -> Int -> Int -> Int -> ST s ()
solutions'' a x y n =
    when (layer x y y n <= limit) $
             do solutions'' a x (y+1) n
                solutions''' a x y y n
 
solutions''' :: STUArray s Int Int -> Int -> Int -> Int -> Int -> ST s ()
solutions''' a x y z n =
    when (layer x y z n <= limit) $
             do readArray a (layer x y z n) >>= return.(+1) >>= writeArray a (layer x y z n)
                solutions''' a x y (z+1) n
 
findSolution :: STUArray s Int Int -> Int -> ST s (Maybe Int)
findSolution a n 
    | n == limit = return Nothing
    | otherwise = do 
        v <- readArray a n
        if v == 1000
            then return (Just n)
            else findSolution a (n+1)
 
main :: IO ()
main = print foo
  where foo = runST $
              do cn <- newArray (0,limit+1) 0 :: ST s (STUArray s Int Int)
                 solutions cn 1
                 findSolution cn 154

[edit] 7 Problem 127

Investigating the number of abc-hits below a given limit.

Solution:

import Data.List
import Data.Array.IArray
import Data.Array.Unboxed
 
main = appendFile "p127.log" $show$ solve 99999
 
rad x = fromIntegral $ product $ map fst $ primePowerFactors $ fromIntegral x
primePowerFactors x = [(head a ,length a)|a<-group$primeFactors x] 
solve :: Int -> Int
solve n = sum [ c | (rc,c) <- invrads
                  , 2 * rc < c
                  , (ra, a) <- takeWhile (\(a,_)->(c > 2*rc*a)) invrads
                  , a < c `div` 2
                  , gcd ra rc == 1
                  , ra * rads ! (c - a) < c `div` rc]
    where
     rads :: UArray Int Int
     rads = listArray (1,n) $ map rad [1..n]
     invrads = sort $ map (\(a,b) -> (b, a)) $ assocs rads
problem_127 = main

[edit] 8 Problem 128

Which tiles in the hexagonal arrangement have prime differences with neighbours?

Solution:

p128=
    concat[m|a<-[0..70000],let m=middle a++right a,not$null m]
    where
    middle n
        |all isPrime [11+6*n,13+6*n,29+12*n]=[2+3*(n+1)*(n+2)]
        |otherwise=[]
    right n
        |all isPrime [11+6*n,17+6*n,17+12*n]=[1+3*(n+2)*(n+3)]
        |otherwise=[]
problem_128=do
    print(p128!!1997)
isPrime x
    |x<100=isPrime' x
    |otherwise=all (millerRabinPrimality x )[2,7,61]

[edit] 9 Problem 129

Investigating minimal repunits that divide by n.

Solution:

import Data.List
factors x=fac$fstfac x
funp (p,1)=
    head[a|
    a<-sort$factors (p-1),
    powMod p 10 a==1
    ]
funp (p,s)=p^(s-1)*funp (p,1)
funn []=1
funn (x:xs) =lcm (funp x) (funn xs)
p129 q=
    head[a|
    a<-[q..],
    gcd a 10==1,
    let s=funn$fstfac$(*9) a,
    s>q,
    s>a
    ]
problem_129 = p129 (10^6)

[edit] 10 Problem 130

Finding composite values, n, for which n−1 is divisible by the length of the smallest repunits that divide it.

Solution:

--factors powMod in p129
fun x 
    |(not$null a)=head a 
    |otherwise=0
    where 
    a=take 1 [n|n<-sort$factors (x-1),(powMod x 10 n)==1]
problem_130 =sum$take 25[a|a<-[1..],
    not$isPrime a,
    let b=fun a, 
    b/=0,
    mod (a-1) b==0,
    mod a 3 /=0]