Difference between revisions of "Euler problems/121 to 130"

From HaskellWiki
Jump to navigation Jump to search
m
 
(10 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.
   
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
  +
import Data.List
problem_121 = undefined
 
  +
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
  +
]
 
</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 35: 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 =
  +
fst . head . dropWhile (\(n,p) -> (2 + 2*n*p) < 10^10) $
head[a+1|a<-[20000,20002..22000],
 
  +
zip [1..] primes
let n=2*(a+1)*primes!!(fromInteger a),
 
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
  +
import Data.Ord (comparing)
primes :: [Integer]
 
  +
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]
 
  +
compress = map head . group
 
  +
primeFactors :: Integer -> [Integer]
 
  +
rad = product . compress . primeFactors
primeFactors n = factor n primes
 
  +
where
 
factor _ [] = []
+
radfax = (1,1) : zip [2..] (map rad [2..])
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]]
 
   
  +
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)
   
  +
problem_125 =
toFloat = (flip encodeFloat 0)
 
  +
fold (+) 0 .
digits n
 
  +
fromList .
{- 123->[3,2,1]
 
  +
concat .
-}
 
  +
L.map (L.filter ispalindrome . sumsFrom) $ [1 .. limit]
|n<10=[n]
 
  +
</haskell>
|otherwise= y:digits x
 
where
 
(x,y)=divMod n 10
 
   
  +
== [http://projecteuler.net/index.php?section=problems&id=126 Problem 126] ==
palind n=foldl dmm 0 (digits n)
 
  +
Exploring the number of cubes required to cover every visible face on a cuboid.
-- 123 ->321
 
dmm=(\x y->x*10+y)
 
   
  +
Solution:
makepalind n=(n*d+p):[c+b*d|b<-[0..9]]
 
  +
<haskell>
where
 
  +
import Data.Array.ST
a=(+1)$floor$logBase 10$fromInteger n
 
  +
import Control.Monad (when)
d=10^a
 
  +
import Control.Monad.ST
p=palind n
 
c=n*10*d+p
 
   
  +
limit = 20000
twomakep n=(n*d+p)
 
  +
layer x y z n = 4*(x+y+z+n-2)*(n-1) + 2*x*y + 2*x*z + 2*y*z
where
 
a=(+1)$floor$logBase 10$fromInteger n
 
d=10^a
 
p=palind n
 
   
  +
solutions :: STUArray s Int Int -> Int -> ST s ()
p125=sum[b|a<-[1..999], b<-makepalind a,not$null$ funa b]
 
  +
solutions a n =
p125a=sum[b|a<-[1000..9999], let b=twomakep a,not$null$ funa b]
 
  +
when (layer 1 1 1 n <= limit) $
p125b=sum[a|a<-[1..9], not$null$ funa a]
 
  +
do solutions a (n+1)
  +
solutions' a 1 n
   
  +
solutions' :: STUArray s Int Int -> Int -> Int -> ST s ()
findmap=fromList[(a,2*fill_map a)|a<-[0..737]]
 
  +
solutions' a x n =
fill_map x
 
|odd x=fastsum $div (x-1) 2
+
when (layer x x x n <= limit) $
|otherwise=fastsumodd (x-1)
+
do solutions' a (x+1) n
  +
solutions'' a x x n
where
 
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
 
   
  +
solutions'' :: STUArray s Int Int -> Int -> Int -> Int -> ST s ()
funa x=[(a,x)|a<-takeWhile (\a->a*a*a<4*x) [2..],funb a x]
 
  +
solutions'' a x y n =
funb x n
 
|odd x=d2==0 && 4*d1>=(x+1)^2 && isSq d1
+
when (layer x y y n <= limit) $
  +
do solutions'' a x (y+1) n
|otherwise=d4==0 && odd d3 && d3>=(x+1)^2 && isSq d3
 
  +
solutions''' a x y y n
where
 
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>
 
   
  +
solutions''' :: STUArray s Int Int -> Int -> Int -> Int -> Int -> ST s ()
== [http://projecteuler.net/index.php?section=view&id=126 Problem 126] ==
 
  +
solutions''' a x y z n =
Exploring the number of cubes required to cover every visible face on a cuboid.
 
  +
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)
Solution:
 
  +
findSolution a n
<haskell>
 
  +
| n == limit = return Nothing
problem_126 = undefined
 
  +
| 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.
   
 
Solution:
 
Solution:
 
<haskell>
 
<haskell>
  +
import Data.List
problem_127 = undefined
 
  +
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
 
</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>
  +
p128=
problem_128 = undefined
 
  +
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>
  +
import Data.List
problem_129 = undefined
 
  +
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>
  +
--factors powMod in p129
import Data.List
 
  +
fun x
mulMod :: Integral a => a -> a -> a -> a
 
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

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
       ]

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

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

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

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]

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

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

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]

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)

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]