Difference between revisions of "Euler problems/171 to 180"
m |
|||
(22 intermediate revisions by 10 users not shown) | |||
Line 2: | Line 2: | ||
Finding numbers for which the sum of the squares of the digits is a square. |
Finding numbers for which the sum of the squares of the digits is a square. |
||
+ | {{sect-stub}} |
||
− | Solution: |
||
− | <haskell> |
||
− | #include <stdio.h> |
||
− | |||
− | static int result = 0; |
||
− | |||
− | #define digits 20 |
||
− | static long long fact[digits+1]; |
||
− | static const long long precision = 1000000000; |
||
− | static const long long precision_mult = 111111111; |
||
− | |||
− | #define maxsquare 64 /* must be a power of 2 > digits * 9^2 */ |
||
− | |||
− | static inline int issquare( int n ) |
||
− | { |
||
− | for( int step = maxsquare/2, i = step;;) |
||
− | { |
||
− | if( i*i == n ) return i; |
||
− | if( !( step >>= 1 ) ) return -1; |
||
− | if( i*i > n ) i -= step; |
||
− | else i += step; |
||
− | } |
||
− | } |
||
− | |||
− | static inline void dodigit( int d, int nr, int sum, long long c, int s ) |
||
− | { |
||
− | if( d ) |
||
− | for( int n = 0; n <= nr; c *= ++n, s += d, sum += d*d ) |
||
− | dodigit( d-1, nr - n, sum, c, s ); |
||
− | else if( issquare( sum ) > 0 ) |
||
− | result = ( s * ( fact[digits] / ( c * fact[nr] ) ) |
||
− | / digits % precision * precision_mult |
||
− | + result ) % precision; |
||
− | } |
||
− | |||
− | int main( void ) |
||
− | { |
||
− | fact[0] = 1; |
||
− | for( int i = 1; i < digits+1; i++ ) fact[i] = fact[i-1]*i; |
||
− | dodigit( 9, digits, 0, 1, 0 ); |
||
− | printf( "%d\n", result ); |
||
− | return 0; |
||
− | } |
||
− | problem_171 = main |
||
− | </haskell> |
||
== [http://projecteuler.net/index.php?section=problems&id=172 Problem 172] == |
== [http://projecteuler.net/index.php?section=problems&id=172 Problem 172] == |
||
Line 85: | Line 41: | ||
Counting the number of "hollow" square laminae that can form one, two, three, ... distinct arrangements. |
Counting the number of "hollow" square laminae that can form one, two, three, ... distinct arrangements. |
||
+ | {{sect-stub}} |
||
− | Solution: |
||
− | <haskell> |
||
− | #include <stdio.h> |
||
− | |||
− | int main() |
||
− | { |
||
− | int a=0; |
||
− | int c=1000000/4; |
||
− | int L[1000000]; |
||
− | int i,x,b; |
||
− | for(i=0;i<=1000000;i++) |
||
− | { |
||
− | L[i]=0; |
||
− | } |
||
− | |||
− | for(x=1;x<=500;x++) |
||
− | { |
||
− | int q=x*x; |
||
− | for(b=1;b<=250000;b++) |
||
− | { |
||
− | int y=q+b*x; |
||
− | if(y<=c){L[y*4]++;} |
||
− | } |
||
− | } |
||
− | |||
− | for(i=0;i<=1000000;i++) |
||
− | {if(L[i]<=10&&L[i]>=1) |
||
− | {a++;} |
||
− | } |
||
− | |||
− | printf( "%d\n", a); |
||
− | return 1; |
||
− | } |
||
− | problem_174 = main |
||
− | </haskell> |
||
== [http://projecteuler.net/index.php?section=problems&id=175 Problem 175] == |
== [http://projecteuler.net/index.php?section=problems&id=175 Problem 175] == |
||
Line 137: | Line 59: | ||
l=length k |
l=length k |
||
p175 x y= |
p175 x y= |
||
− | + | concat $ intersperse "," $ |
|
− | + | map show $reverse $filter (/=0)$findRat x y |
|
problems_175=p175 123456789 987654321 |
problems_175=p175 123456789 987654321 |
||
test=p175 13 17 |
test=p175 13 17 |
||
Line 162: | Line 84: | ||
Integer angled Quadrilaterals. |
Integer angled Quadrilaterals. |
||
+ | {{sect-stub}} |
||
− | Solution: |
||
− | <haskell> |
||
− | problem_177 = undefined |
||
− | </haskell> |
||
== [http://projecteuler.net/index.php?section=problems&id=178 Problem 178] == |
== [http://projecteuler.net/index.php?section=problems&id=178 Problem 178] == |
||
Step Numbers |
Step Numbers |
||
+ | |||
− | Solution: |
||
+ | Count pandigital step numbers. |
||
<haskell> |
<haskell> |
||
+ | import qualified Data.Map as M |
||
− | problem_178 = undefined |
||
+ | |||
+ | data StepState a = StepState { minDigit :: a |
||
+ | , maxDigit :: a |
||
+ | , lastDigit :: a |
||
+ | } deriving (Show, Eq, Ord) |
||
+ | |||
+ | isSolution (StepState i a _) = i == 0 && a == 9 |
||
+ | neighborStates m s@(StepState i a n) = map (\x -> (x, M.findWithDefault 0 s m)) $ |
||
+ | [StepState (min i (n - 1)) a (n - 1), StepState i (max a (n + 1)) (n + 1)] |
||
+ | |||
+ | allStates = [StepState i a n | (i, a) <- range ((0, 0), (9, 9)), n <- range (i, a)] |
||
+ | initialState = M.fromDistinctAscList [(StepState i i i, 1) | i <- [1..9]] |
||
+ | stepState m = M.fromListWith (+) $ allStates >>= neighborStates m |
||
+ | numSolutionsInMap = sum . map snd . filter (isSolution . fst) . M.toList |
||
+ | numSolutionsOfSize n = sum . map numSolutionsInMap . take n $ iterate stepState initialState |
||
+ | |||
+ | problem_178 = numSolutionsOfSize 40 |
||
</haskell> |
</haskell> |
||
== [http://projecteuler.net/index.php?section=problems&id=179 Problem 179] == |
== [http://projecteuler.net/index.php?section=problems&id=179 Problem 179] == |
||
Consecutive positive divisors. |
Consecutive positive divisors. |
||
+ | See http://en.wikipedia.org/wiki/Divisor_function for a simple |
||
− | Solution: |
||
+ | explanation of calculating the number of divisors of an integer, |
||
+ | based on its prime factorization. Then, if you have a lot of |
||
+ | time on your hands, run the following program. You need to load |
||
+ | the Factoring library from David Amos' wonderful Maths library. |
||
+ | See: http://www.polyomino.f2s.com/david/haskell/main.html |
||
+ | |||
<haskell> |
<haskell> |
||
+ | import Factoring |
||
− | #include <stdio.h> |
||
+ | import Data.List |
||
+ | nFactors :: Integer -> Int |
||
− | #define SZ 10000000 |
||
+ | nFactors n = |
||
− | int n[SZ + 1]; |
||
+ | let a = primePowerFactorsL n |
||
+ | in foldl' (\x y -> x * ((snd y)+1) ) 1 a |
||
+ | countConsecutiveInts l = foldl' (\x y -> if y then x+1 else x) 0 a |
||
− | int main () |
||
+ | where a = zipWith (==) l (tail l) |
||
− | { |
||
− | int i, j; |
||
− | for (i = 0; i <= SZ; i++) |
||
− | n[i] = 1; |
||
+ | problem_179 = countConsecutiveInts $ map nFactors [2..(10^7 - 1)] |
||
− | for (i = 2; i <= SZ; i++) |
||
− | for (j = i; j <= SZ; j += i) |
||
− | n[j] += 1; |
||
+ | main = print problem_179 |
||
− | j = 0; |
||
− | for (i = 1; i < SZ; i++) |
||
− | if (n[i] == n[i + 1]) |
||
− | j++; |
||
− | printf ("%d\n", j); |
||
− | return 0; |
||
− | } |
||
− | problem_179 = main |
||
</haskell> |
</haskell> |
||
+ | |||
+ | This is all well and good, but it runs very slowly. (About 4 |
||
+ | minutes on my machine) We have to factor every number between 2 |
||
+ | and 10^7, which on a non Quantum CPU takes a while. There is |
||
+ | another way! |
||
+ | |||
+ | We can sieve for the answer. Every number has 1 for a factor. |
||
+ | Every other number has 2 as a factor, and every third number has |
||
+ | 3 as a factor. So we run a sieve that counts (increments) |
||
+ | itself for every integer. When we are done, we run through the |
||
+ | resulting array and look at neighboring elements. If they are |
||
+ | equal, we increment a counter. This version runs in about 9 |
||
+ | seconds on my machine. HenryLaxen May 14, 2008 |
||
+ | |||
+ | <haskell> |
||
+ | {-# OPTIONS -O2 -optc-O #-} |
||
+ | import Data.Array.ST |
||
+ | import Data.Array.Unboxed |
||
+ | import Control.Monad |
||
+ | import Control.Monad.ST |
||
+ | import Data.List |
||
+ | |||
+ | r1 = (2,(10^7-1)) |
||
+ | |||
+ | type Sieve s = STUArray s Int Int |
||
+ | |||
+ | incN :: Sieve s -> Int -> ST s () |
||
+ | incN a n = do |
||
+ | x <- readArray a n |
||
+ | writeArray a n (x+1) |
||
+ | |||
+ | incEveryN :: Sieve s -> Int -> ST s () |
||
+ | incEveryN a n = mapM_ (incN a) [n,n+n..snd r1] |
||
+ | |||
+ | sieve :: Int |
||
+ | sieve = countConsecutiveInts b |
||
+ | where b = runSTUArray $ |
||
+ | do a <- newArray r1 1 :: ST s (STUArray s Int Int) |
||
+ | mapM_ (incEveryN a) [fst r1 .. (snd r1) `div` 2] |
||
+ | return a |
||
+ | |||
+ | countConsecutiveInts :: UArray Int Int -> Int |
||
+ | countConsecutiveInts a = |
||
+ | let r1 = [fst (bounds a) .. snd (bounds a) - 1] |
||
+ | in length $ filter (\y -> a ! y == a ! (y+1)) $ r1 |
||
+ | |||
+ | main = print sieve |
||
+ | </haskell> |
||
+ | |||
== [http://projecteuler.net/index.php?section=problems&id=180 Problem 180] == |
== [http://projecteuler.net/index.php?section=problems&id=180 Problem 180] == |
||
Line 208: | Line 191: | ||
Solution: |
Solution: |
||
<haskell> |
<haskell> |
||
+ | import Data.Ratio |
||
− | problem_180 = undefined |
||
+ | |||
+ | {- |
||
+ | After some algebra, we find: |
||
+ | f1 n x y z = x^(n+1) + y^(n+1) - z^(n+1) |
||
+ | f2 n x y z = (x*y + y*z + z*x) * ( x^(n-1) + y^(n-1) - z^(n-1) ) |
||
+ | f3 n x y z = x*y*z*( x^(n-2) + y^(n-2) - z^(n-2) ) |
||
+ | f n x y z = f1 n x y z + f2 n x y z - f3 n x y z |
||
+ | f n x y z = (x+y+z) * (x^n+y^n-z^n) |
||
+ | Now the hard part comes in realizing that n can be negative. |
||
+ | Thanks to Fermat, we only need examine the cases n = [-2, -1, 1, 2] |
||
+ | Which leads to: |
||
+ | |||
+ | f(-2) z = xy/sqrt(x^2 + y^2) |
||
+ | f(-1) z = xy/(x+y) |
||
+ | f(1) z = x+y |
||
+ | f(2) z = sqrt(x^2 + y^2) |
||
+ | |||
+ | -} |
||
+ | |||
+ | unique :: Eq(a) => [a] -> [a] |
||
+ | unique [] = [] |
||
+ | unique (x:xs) | elem x xs = unique xs |
||
+ | | otherwise = x : unique xs |
||
+ | |||
+ | -- Not quite correct, but I don't care about the zeros |
||
+ | ratSqrt :: Rational -> Rational |
||
+ | ratSqrt x = |
||
+ | let a = floor $ sqrt $ fromIntegral $ numerator x |
||
+ | b = floor $ sqrt $ fromIntegral $ denominator x |
||
+ | c = (a%b) * (a%b) |
||
+ | in if x == c then (a%b) else 0 |
||
+ | |||
+ | -- Not quite correct, but I don't care about the zeros |
||
+ | reciprocal :: Rational -> Rational |
||
+ | reciprocal x |
||
+ | | x == 0 = 0 |
||
+ | | otherwise = denominator x % numerator x |
||
+ | |||
+ | problem_180 = |
||
+ | let order = 35 |
||
+ | range :: [Rational] |
||
+ | range = unique [ (a%b) | b <- [1..order], a <- [1..(b-1)] ] |
||
+ | fm2,fm1,f1,f2 :: [[Rational]] |
||
+ | fm2 = [[x,y,z] | x<-range, y<-range, |
||
+ | let z = x*y * reciprocal (ratSqrt(x*x+y*y)), elem z range] |
||
+ | fm1 = [[x,y,z] | x<-range, y<-range, |
||
+ | let z = x*y * reciprocal (x+y), elem z range] |
||
+ | f1 = [[x,y,z] | x<-range, y<-range, |
||
+ | let z = (x+y), elem z range] |
||
+ | f2 = [[x,y,z] | x<-range, y<-range, |
||
+ | let z = ratSqrt(x*x+y*y), elem z range] |
||
+ | result = sum $ unique $ map (\x -> sum x) (fm2++fm1++f1++f2) |
||
+ | in (numerator result + denominator result) |
||
+ | |||
</haskell> |
</haskell> |
Latest revision as of 01:49, 13 February 2010
Problem 171
Finding numbers for which the sum of the squares of the digits is a square.
Problem 172
Investigating numbers with few repeated digits.
Solution:
factorial n = product [1..toInteger n]
fallingFactorial x n = product [x - fromInteger i | i <- [0..toInteger n - 1] ]
choose n k = fallingFactorial n k `div` factorial k
-- how many numbers can we get having d digits and p positions
p172 0 _ = 0
p172 d p
| p < 4 = d^p
| otherwise =
(p172' p) + p*(p172' (p-1)) + (choose p 2)*(p172' (p-2)) + (choose p 3)*(p172' (p-3))
where
p172' = p172 (d-1)
problem_172= (p172 10 18) * 9 `div` 10
Problem 173
Using up to one million tiles how many different "hollow" square laminae can be formed? Solution:
problem_173=
let c=div (10^6) 4
xm=floor$sqrt $fromIntegral c
k=[div c x|x<-[1..xm]]
in sum k-(div (xm*(xm+1)) 2)
Problem 174
Counting the number of "hollow" square laminae that can form one, two, three, ... distinct arrangements.
Problem 175
Fractions involving the number of different ways a number can be expressed as a sum of powers of 2. Solution:
sternTree x 0=[]
sternTree x y=
m:sternTree y n
where
(m,n)=divMod x y
findRat x y
|odd l=take (l-1) k++[last k-1,1]
|otherwise=k
where
k=sternTree x y
l=length k
p175 x y=
concat $ intersperse "," $
map show $reverse $filter (/=0)$findRat x y
problems_175=p175 123456789 987654321
test=p175 13 17
Problem 176
Rectangular triangles that share a cathetus. Solution:
--k=47547
--2*k+1=95095 = 5*7*11*13*19
lst=[5,7,11,13,19]
primes=[2,3,5,7,11]
problem_176 =
product[a^b|(a,b)<-zip primes (reverse n)]
where
la=div (last lst+1) 2
m=map (\x->div x 2)$init lst
n=m++[la]
Problem 177
Integer angled Quadrilaterals.
Problem 178
Step Numbers
Count pandigital step numbers.
import qualified Data.Map as M
data StepState a = StepState { minDigit :: a
, maxDigit :: a
, lastDigit :: a
} deriving (Show, Eq, Ord)
isSolution (StepState i a _) = i == 0 && a == 9
neighborStates m s@(StepState i a n) = map (\x -> (x, M.findWithDefault 0 s m)) $
[StepState (min i (n - 1)) a (n - 1), StepState i (max a (n + 1)) (n + 1)]
allStates = [StepState i a n | (i, a) <- range ((0, 0), (9, 9)), n <- range (i, a)]
initialState = M.fromDistinctAscList [(StepState i i i, 1) | i <- [1..9]]
stepState m = M.fromListWith (+) $ allStates >>= neighborStates m
numSolutionsInMap = sum . map snd . filter (isSolution . fst) . M.toList
numSolutionsOfSize n = sum . map numSolutionsInMap . take n $ iterate stepState initialState
problem_178 = numSolutionsOfSize 40
Problem 179
Consecutive positive divisors. See http://en.wikipedia.org/wiki/Divisor_function for a simple explanation of calculating the number of divisors of an integer, based on its prime factorization. Then, if you have a lot of time on your hands, run the following program. You need to load the Factoring library from David Amos' wonderful Maths library. See: http://www.polyomino.f2s.com/david/haskell/main.html
import Factoring
import Data.List
nFactors :: Integer -> Int
nFactors n =
let a = primePowerFactorsL n
in foldl' (\x y -> x * ((snd y)+1) ) 1 a
countConsecutiveInts l = foldl' (\x y -> if y then x+1 else x) 0 a
where a = zipWith (==) l (tail l)
problem_179 = countConsecutiveInts $ map nFactors [2..(10^7 - 1)]
main = print problem_179
This is all well and good, but it runs very slowly. (About 4 minutes on my machine) We have to factor every number between 2 and 10^7, which on a non Quantum CPU takes a while. There is another way!
We can sieve for the answer. Every number has 1 for a factor. Every other number has 2 as a factor, and every third number has 3 as a factor. So we run a sieve that counts (increments) itself for every integer. When we are done, we run through the resulting array and look at neighboring elements. If they are equal, we increment a counter. This version runs in about 9 seconds on my machine. HenryLaxen May 14, 2008
{-# OPTIONS -O2 -optc-O #-}
import Data.Array.ST
import Data.Array.Unboxed
import Control.Monad
import Control.Monad.ST
import Data.List
r1 = (2,(10^7-1))
type Sieve s = STUArray s Int Int
incN :: Sieve s -> Int -> ST s ()
incN a n = do
x <- readArray a n
writeArray a n (x+1)
incEveryN :: Sieve s -> Int -> ST s ()
incEveryN a n = mapM_ (incN a) [n,n+n..snd r1]
sieve :: Int
sieve = countConsecutiveInts b
where b = runSTUArray $
do a <- newArray r1 1 :: ST s (STUArray s Int Int)
mapM_ (incEveryN a) [fst r1 .. (snd r1) `div` 2]
return a
countConsecutiveInts :: UArray Int Int -> Int
countConsecutiveInts a =
let r1 = [fst (bounds a) .. snd (bounds a) - 1]
in length $ filter (\y -> a ! y == a ! (y+1)) $ r1
main = print sieve
Problem 180
Rational zeros of a function of three variables. Solution:
import Data.Ratio
{-
After some algebra, we find:
f1 n x y z = x^(n+1) + y^(n+1) - z^(n+1)
f2 n x y z = (x*y + y*z + z*x) * ( x^(n-1) + y^(n-1) - z^(n-1) )
f3 n x y z = x*y*z*( x^(n-2) + y^(n-2) - z^(n-2) )
f n x y z = f1 n x y z + f2 n x y z - f3 n x y z
f n x y z = (x+y+z) * (x^n+y^n-z^n)
Now the hard part comes in realizing that n can be negative.
Thanks to Fermat, we only need examine the cases n = [-2, -1, 1, 2]
Which leads to:
f(-2) z = xy/sqrt(x^2 + y^2)
f(-1) z = xy/(x+y)
f(1) z = x+y
f(2) z = sqrt(x^2 + y^2)
-}
unique :: Eq(a) => [a] -> [a]
unique [] = []
unique (x:xs) | elem x xs = unique xs
| otherwise = x : unique xs
-- Not quite correct, but I don't care about the zeros
ratSqrt :: Rational -> Rational
ratSqrt x =
let a = floor $ sqrt $ fromIntegral $ numerator x
b = floor $ sqrt $ fromIntegral $ denominator x
c = (a%b) * (a%b)
in if x == c then (a%b) else 0
-- Not quite correct, but I don't care about the zeros
reciprocal :: Rational -> Rational
reciprocal x
| x == 0 = 0
| otherwise = denominator x % numerator x
problem_180 =
let order = 35
range :: [Rational]
range = unique [ (a%b) | b <- [1..order], a <- [1..(b-1)] ]
fm2,fm1,f1,f2 :: [[Rational]]
fm2 = [[x,y,z] | x<-range, y<-range,
let z = x*y * reciprocal (ratSqrt(x*x+y*y)), elem z range]
fm1 = [[x,y,z] | x<-range, y<-range,
let z = x*y * reciprocal (x+y), elem z range]
f1 = [[x,y,z] | x<-range, y<-range,
let z = (x+y), elem z range]
f2 = [[x,y,z] | x<-range, y<-range,
let z = ratSqrt(x*x+y*y), elem z range]
result = sum $ unique $ map (\x -> sum x) (fm2++fm1++f1++f2)
in (numerator result + denominator result)