Project Euler
Bei Project Euler handelt es sich um eine Webseite mit einer Art "Programmierwettbewerb" für mehr oder weniger komplexe mathematische Problemstellungen, in erster Linie zahlentheoretischer Natur. Das Problem (bzw. der Reiz) der meisten Aufgaben ist, dass sie prinzipiell sehr leicht zu lösen sind, die Lösung, auf die man "direkt" kommt aber meistens extrem ineffizient ist und man sich etwas mit dem mathematischen Background beschäftigen muss, um den eigenen Algorithmus zu optimieren. Da ich schon lange die Programmiersprache Ruby lernen wollte war das eine gute Gelegenheit für mich.
Die meisten meiner Lösungen sind nicht besonders effizient (und teilweise vermutlich auch mathematisch nicht wirklich optimal). Mein Ziel war es Ruby zu lernen, nicht die Aufgaben möglichst geschickt zu lösen. Dennoch sind fast alle meine Lösungen in deutlich weniger als einer Minute (die meisten sogar in weniger als einer Sekunde auf einem halbwegs aktuellen Prozessor) ausführbar (und das obwohl Ruby eine relativ langsam interpretierte Sprache ist).
Viele der Aufgaben sind etwas eleganter lösbar, wenn man Ruby Libraries benutzt (z.B. die Prime Klasse aus 'mathn'). Ich habe darauf absichtlich verzichtet, da ich alle Algorithmen selbst implementieren wollte.
Achtung: Viele Leute beschweren sich darüber, dass im Netz Lösungen zu den Aufgaben veröffentlicht werden. Ich habe kein Problem damit, im Gegenteil, ich finde es sinnvoll, dass Lösungen veröffentlicht werden damit man sich auch andere Ansätze anschauen und dadurch noch mehr über das Problem lernen kann. Bis auf ein paar wenige Ausnahmen habe ich alle Probleme vollständig selbst gelöst und mir erst im Nachhinein die Programme anderer angeschaut. Wer die Lösungen einfach nur kopiert um möglichst viele Probleme abzuhaken ist selbst schuld! Dadurch verdirbt man sich nur den Spass ohne jeglichen Nutzen davon zu haben.
Gelöste Probleme: 80 (Stufe 2 von 5).
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
016 017 018 019 020 021 022 023 024 025 026 027 028 029 030
031 032 033 034 035 036 037 038 039 040 041 042 043 044 045
046 047 048 049 050 051 052 053 054 055 056 057 058 059 060
061 062 063 064 065 066 067 068 069 070 071 072 073 074 075
076 077 078 079 080 081 082 083 084 085 086 087 088 089 090
091 092 093 094 095 096 097 098 099 100 101 102 103 104 105
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
196 197 198 199 200 201 202 203 204 205 206
Problem 1
Find the sum of all the multiples of 3 or 5 below 1000.n = 1000 def gauss(n) n*(n+1)/2 end puts 3*gauss((n-1)/3) + 5*gauss((n-1)/5) - 15*gauss((n-1)/15)Stichwort kleiner Gauss.
Problem 2
Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed four million.a,b,sum = 1,1,0 while a < 4*(10**6) do sum += a if a%2==0 a, b = b, a+b end puts sum
Problem 3
What is the largest prime factor of the number 600851475143 ?n = 600851475143 i = 2 while n>1 do n, i = n/i, i-1 if n%i == 0 i += 1 end puts iDiese Lösung gefällt mir sehr gut. Sie ist extrem schnell (O(n1/2 log2(n))), gleichzeitig sehr einfach zu verstehen und benutzt nur indirekt irgendwelche Eigenschaften von Primzahlen. Ein Beweis der Korrektheit findet sich in Primality testing in deterministic polynomial time von Professor Michiel Smid (Seite 24 und 25).
Problem 4
Find the largest palindrome made from the product of two 3-digit numbers.
max = 0
for i in [*100..999].reverse do
for j in [*i..999].reverse do
next if ( i%11 != 0 ) and ( j%11 != 0 )
x = i*j
max = [max,x].max if x.to_s == x.to_s.reverse
end
end
puts max
Optimierung: Palindrome gerader Länge sind immer durch 11 teilbar.
Problem 5
What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?
def gcd(a,b) return (b==0) ? a : gcd(b, a % b) end
puts [*1..20].inject(1){ |s,x| s*x / gcd(s,x) }
Stichwort kleinstes gemeinsames Vielfaches.
Problem 6
Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.n = 100 puts ( ( n*(n+1)/2 ) ** 2 ) - ( n*(n+1)*(2*n+1) / 6 )Stichwort Gaussche Summenformeln.
Problem 7
What is the 10001st prime number?require 'primetool' # Nach Primzahlsatz: 10001 <= 120000 / ln(120000) = 10260 p = PrimeTool.new(120000) puts p.prime(10001)Stichwort Primzahlsatz und Primzahlsieb.
Problem 8
Find the greatest product of five consecutive digits in the 1000-digit number.
n = <<EOF
73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450
EOF
n = n.gsub("\n",'').split(//)
max = 0
for j in 0..n.length-5
max = [max, [*0..4].map{ |i| n[j+i].to_i }.inject(1){ |t,i| t * i } ].max
end
puts max
Problem 9
There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product abc.
for a in 1..997 do
for b in a..998 do
c = 1000 - a - b
if a*a + b*b == c*c
puts a*b*c
exit
end
end
end
Problem 10
Find the sum of all the primes below two million.require 'primetool' n = 2 * (10**6) p = PrimeTool.new(n) puts [*2..n].inject(0){ |s,i| s + ((p.is_prime?(i)) ? i : 0) }
Problem 11
What is the greatest product of four adjacent numbers in any direction (up, down, left, right, or diagonally) in the 20x20 grid?
@data = <<EOF
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
EOF
@data = @data.gsub("\n", " ").split(/ /)
def grid(i,j)
return 0 if i<0 or i>19 or j<0 or j>19
return @data[j + 20*i].to_i
end
def prod(i,j,idir,jdir)
return grid(i,j) * grid(i+idir,j+jdir) * grid(i+2*idir,j+2*jdir) * grid(i+3*idir,j+3*jdir)
end
max = 0
for i in 1..19 do
for j in 1..19 do
for idir in [-1,0,1] do
for jdir in [0,1] do
next if jdir == idir and idir == 0
max = [max, prod(i,j,idir,jdir)].max
end
end
end
end
puts max
Nicht so schön. Mehr oder weniger Brute Force, läuft aber in wenigen Millisekunden.
Problem 12
What is the value of the first triangle number to have over five hundred divisors?
limit = 500
def d(n)
c,i = 2,2
# Bis sqrt(n) testen reicht, dann direkt 2 zählen
while i*i < n do
c += 2 if n%i == 0
i += 1
end
return c
end
m,t,i = 0,1,1
while m <= limit do
t = i*(i+1)/2
# i und i+1 sind teilerfremd und d(n) ist zahlentheoretisch
a = (i%2==0) ? [i/2,i+1] : [i,(i+1)/2]
m = d(a[0]) * d(a[1])
i += 1
end
puts t
- Idee 1: Die Teileranzahlfunktion ist zahlentheoretisch (und n, n+1 sind teilerfremd)
- Idee 2: Für jeden Teiler k < sqrt(n) ist n/k > sqrt(n)
Problem 13
Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.
n = %w{
37107287533902102798797998220837590246510135740250
46376937677490009712648124896970078050417018260538
74324986199524741059474233309513058123726617309629
91942213363574161572522430563301811072406154908250
23067588207539346171171980310421047513778063246676
89261670696623633820136378418383684178734361726757
28112879812849979408065481931592621691275889832738
44274228917432520321923589422876796487670272189318
47451445736001306439091167216856844588711603153276
70386486105843025439939619828917593665686757934951
62176457141856560629502157223196586755079324193331
64906352462741904929101432445813822663347944758178
92575867718337217661963751590579239728245598838407
58203565325359399008402633568948830189458628227828
80181199384826282014278194139940567587151170094390
35398664372827112653829987240784473053190104293586
86515506006295864861532075273371959191420517255829
71693888707715466499115593487603532921714970056938
54370070576826684624621495650076471787294438377604
53282654108756828443191190634694037855217779295145
36123272525000296071075082563815656710885258350721
45876576172410976447339110607218265236877223636045
17423706905851860660448207621209813287860733969412
81142660418086830619328460811191061556940512689692
51934325451728388641918047049293215058642563049483
62467221648435076201727918039944693004732956340691
15732444386908125794514089057706229429197107928209
55037687525678773091862540744969844508330393682126
18336384825330154686196124348767681297534375946515
80386287592878490201521685554828717201219257766954
78182833757993103614740356856449095527097864797581
16726320100436897842553539920931837441497806860984
48403098129077791799088218795327364475675590848030
87086987551392711854517078544161852424320693150332
59959406895756536782107074926966537676326235447210
69793950679652694742597709739166693763042633987085
41052684708299085211399427365734116182760315001271
65378607361501080857009149939512557028198746004375
35829035317434717326932123578154982629742552737307
94953759765105305946966067683156574377167401875275
88902802571733229619176668713819931811048770190271
25267680276078003013678680992525463401061632866526
36270218540497705585629946580636237993140746255962
24074486908231174977792365466257246923322810917141
91430288197103288597806669760892938638285025333403
34413065578016127815921815005561868836468420090470
23053081172816430487623791969842487255036638784583
11487696932154902810424020138335124462181441773470
63783299490636259666498587618221225225512486764533
67720186971698544312419572409913959008952310058822
95548255300263520781532296796249481641953868218774
76085327132285723110424803456124867697064507995236
37774242535411291684276865538926205024910326572967
23701913275725675285653248258265463092207058596522
29798860272258331913126375147341994889534765745501
18495701454879288984856827726077713721403798879715
38298203783031473527721580348144513491373226651381
34829543829199918180278916522431027392251122869539
40957953066405232632538044100059654939159879593635
29746152185502371307642255121183693803580388584903
41698116222072977186158236678424689157993532961922
62467957194401269043877107275048102390895523597457
23189706772547915061505504953922979530901129967519
86188088225875314529584099251203829009407770775672
11306739708304724483816533873502340845647058077308
82959174767140363198008187129011875491310547126581
97623331044818386269515456334926366572897563400500
42846280183517070527831839425882145521227251250327
55121603546981200581762165212827652751691296897789
32238195734329339946437501907836945765883352399886
75506164965184775180738168837861091527357929701337
62177842752192623401942399639168044983993173312731
32924185707147349566916674687634660915035914677504
99518671430235219628894890102423325116913619626622
73267460800591547471830798392868535206946944540724
76841822524674417161514036427982273348055556214818
97142617910342598647204516893989422179826088076852
87783646182799346313767754307809363333018982642090
10848802521674670883215120185883543223812876952786
71329612474782464538636993009049310363619763878039
62184073572399794223406235393808339651327408011116
66627891981488087797941876876144230030984490851411
60661826293682836764744779239180335110989069790714
85786944089552990653640447425576083659976645795096
66024396409905389607120198219976047599490197230297
64913982680032973156037120041377903785566085089252
16730939319872750275468906903707539413042652315011
94809377245048795150954100921645863754710598436791
78639167021187492431995700641917969777599028300699
15368713711936614952811305876380278410754449733078
40789923115535562561142322423255033685442488917353
44889911501440648020369068063960672322193204149535
41503128880339536053299340368006977710650566631954
81234880673210146739058568557934581403627822703280
82616570773948327592232845941706525094512325230608
22918802058777319719839450180888072429661980811197
77158542502016545090413245809786882778948721859617
72107838435069186155435662884062257473692284509516
20849603980134001723930671666823555245252804609722
53503534226472524250874054075591789781264330331690
}
puts n.map{|x| x.to_i}.inject(0){ |s,i| s+i }.to_s[0..9]
Problem 14
The following iterative sequence is defined for the set of positive integers:n -> n/2 (n is even)
n -> 3n + 1 (n is odd)
Which starting number, under one million, produces the longest chain?
n = 10**6
table = { 1 => 1 }
max = [0,0]
# OBdA nur ungerade Zahlen betrachten; Zu jeder geraden gibt es eine
# ungerade, die eine längere Kette erzeugt
1.step(n,2) do |i|
c,m = 0,i
while table[m].nil? do
c += 1
m = (m%2==0) ? m/2 : 3*m+1
end
table[i] = c + table[m]
max = [table[i],i] if max[0]<table[i]
end
puts max[1]
Stichwort Dynamic Programming.
Problem 15
How many routes are there through a 20x20 grid?
n = 20
table = []
for i in 0..n
table[i] = []
table[i][n] = 1
end
for j in 0..n do
table[n][j] = 1
end
for i in [*0..(n-1)].reverse do
for j in [*0..(n-1)].reverse do
table[i][j] = table[i+1][j] + table[i][j+1]
end
end
puts table[0][0]
Stichwort Dynamic Programming.
Problem 16
What is the sum of the digits of the number 21000?
puts (2**1000).to_s.split(//).inject(0){ |s,x| s+x.to_i }
Naja, das geht bestimmt auch "mathematischer" :-)
Problem 17
If all the numbers from 1 to 1000 ("one thousand") inclusive were written out in words, how many letters would be used?
@names = [ "",
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen", "twenty"
]
@names[ 30] = "thirty"
@names[ 40] = "forty"
@names[ 50] = "fifty"
@names[ 60] = "sixty"
@names[ 70] = "seventy"
@names[ 80] = "eighty"
@names[ 90] = "ninety"
@names[ 100] = "hundred"
@names[1000] = "one thousand"
def name(n)
return @names[n] if @names[n]
return name(n/10*10) + "-" + name(n%10) if n<100
return name(n/100) + " " + name(100) + ( (n%100 > 0) ? (" and " + name(n%100)) : "" )
end
sum = 3 # "one" bei 100 fehlt ("hundred")
for i in 1..1000 do
sum += name(i).gsub(/ |-/, "").length
end
puts sum
Problem 18
Find the maximum total from top to bottom of the triangle below.
triangle = [
[75],
[95, 64],
[17, 47, 82],
[18, 35, 87, 10],
[20, 04, 82, 47, 65],
[19, 01, 23, 75, 03, 34],
[88, 02, 77, 73, 07, 63, 67],
[99, 65, 04, 28, 06, 16, 70, 92],
[41, 41, 26, 56, 83, 40, 80, 70, 33],
[41, 48, 72, 33, 47, 32, 37, 16, 94, 29],
[53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14],
[70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57],
[91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48],
[63, 66, 04, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31],
[04, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 04, 23]
]
(triangle.length-2).downto(0) { |i|
for j in 0..(triangle[i].length-1) do
triangle[i][j] += [triangle[i+1][j], triangle[i+1][j+1]].max
end
}
puts triangle[0][0]
Problem 19
How many Sundays fell on the first of the month during the twentieth century?
def dow(q,m,y)
if m<=2 then m+=12; y-=1; end
j = y / 100
k = y - 100*j
return ( q + ((m+1)*26)/10 + k + k/4 + j/4 - 2 * j ) % 7
end
sum = 0
for month in 1..12 do
for year in 1..100 do
sum += 1 if dow(1,month,1900+year) == 1
end
end
puts sum
Idee: Zellers Kongruenz. Hätte man einfacher haben können mit den Ruby Date Funktionen, wollte ich aber nicht.
Problem 20
Find the sum of digits in 100!
def fac(n) return (n==1) ? 1 : n*fac(n-1) end
puts fac(100).to_s.split(//).inject(0){ |s,x| s+x.to_i }
Siehe Problem 16.
Problem 21
Let d(n) be defined as the sum of proper divisors of n. If d(a) = b and d(b) = a, where a != b, then a and b are an amicable pair and each of a and b are called amicable numbers. Evaluate the sum of all the amicable numbers under 10000.
n = 10**4
def dsum(n)
c,i = 1,2
# Nur bis sqrt(n) testen und dafür dann doppelt zählen
while i*i < n do
c += i + n/i if n%i == 0
i += 1
end
return c
end
sum = 0
for i in 1..(n-1) do
j = dsum(i)
next if i==j
sum += i if i == dsum(j)
end
puts sum
Problem 22
Using names.txt, a text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score. For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714. What is the total of all the name scores in the file?
d = File.open("22_names.txt").read.gsub('"','').split(/,/).sort
puts d.each_index.inject(0){ |s,i| s + ( d[i].split(//).inject(0){ |s,c| s+c[0]-"@"[0] } * (i+1) ) }
Schön kurz! Fast so unlesbar wie Perl Code :-)
Problem 23
It can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
max = 28123
def dsum(n)
return 0 if n==1
s, i = 1, 2
while i*i < n do
s += i + n/i if n%i == 0
i += 1
end
s += i if i*i == n
return s
end
abundants = []
n = []
0.upto(max-1) { |i| n[i] = i+1; abundants << n[i] if dsum(n[i])>n[i] }
l = abundants.length
0.upto(l-1) do |i|
i.upto(l-1) do |j|
k = abundants[i] + abundants[j] - 1
n[k] = 0 if k < max
end
end
puts n.inject(0){ |s,k| s+k }
Doofe Lösung für eine doofe Aufgabe.
Problem 24
What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?n = 10**6 def fac(n) return 1 if n==1 return n*fac(n-1) end def perm(a,k) return a[0] if a.length == 1 f = fac(a.length - 1) i = k / f s = a[i] a.delete_at(i) return [s, perm(a, k - f * i)] end puts perm([0,1,2,3,4,5,6,7,8,9], n-1).to_sHier muss ich zugeben, dass ich nur auf extrem langsame Lösungen gekommen bin und daher etwas gegooglet habe. Die Idee ist von Chris Smith geklaut.
Problem 25
What is the first term in the Fibonacci sequence to contain 1000 digits?a = b = i = 1 while a.to_s.length < 1000 do a, b, i = b, a+b, i+1 end puts i
Problem 26
Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.
n = 1000
def divrest(a,b)
rems = []
r = 1
while r != 0 do
k = a/b
if k==0 then
a *= 10
k = a/b
end
r = a%b
if not rems.include?(r) then
rems << r
else
break
end
a = r
end
return rems.length
end
max = [0,0]
1.upto(n-1){ |i|
k = divrest(1,i)
max = [k,i] if k>max[0]
}
puts max[1]
Mögliche Optimierung: Zahlen mit endlicher Entwicklung von vornerein ausschliessen (das sind genau die, die keine anderen Primteiler als 2 oder 5 haben).
Problem 27
Euler published the remarkable quadratic formula: n2 + n + 41. It turns out that the formula will produce 40 primes for the consecutive values n = 0 to 39. Considering quadratics of the form: n2 + an + b, where |a| < 1000 and |b| < 1000. Find the product of the coefficients, a and b, for the quadratic expression that produces the maximum number of primes for consecutive values of n, starting with n = 0.require 'primetool' maxab = 1000-1 @pt = PrimeTool.new(100*100 + 100*maxab + maxab) def primes(a,b) primes = 0 1.upto(100){ |n| if @pt.is_prime?(n*(n+a)+b) then primes += 1 else break end } primes end max = [0,0,0] @pt.primes.select{ |b| b <= maxab }.each do |b| @pt.primes.each do |p| a = p-b-1 next if a < -maxab break if a > maxab k = primes(a,b) max = [k,a,b] if max[0] < k end end puts max[1]*max[2]Sehr interessante Aufgabe (siehe auch hier)! Ideen: an n=0 sieht man, dass b prim sein muss (und positiv) und an n=1 sieht man, dass a+b+1 ebenfalls prim sein muss.
Problem 28
Starting with the number 1 and moving to the right in a clockwise direction a n by n spiral is formed. What is the sum of both diagonals in a 1001 by 1001 spiral?
n = 1001
diagonals = []
sum, k = 1, 2
while true do
break if diagonals.length > 2*n-1
4.times{ |i| diagonals << sum+i*k }
sum += 4*k
k += 2
end
puts diagonals[0..2*n-2].inject(0){ |s,x| s+x }
Nette Aufgabe, nicht soo schöne Lösung, aber schnell (< 1 ms).
Problem 29
How many distinct terms are in the sequence generated by ab for 2 <= a,b <= 100?
puts (2..100).map{ |i| (2..100).map{ |j| [i**j, j**i] } }.flatten.sort.uniq.length
Ziemlich straight-forward und schön kurz :-)
Problem 30
Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.
@values = [0,1,32,243,1024,3125,7776,16807,32768,59049]
@table = []
def sum(n)
return @values[n] if n<10
return @table[n] if @table[n]
@table[n] = @values[n%10] + sum(n / 10)
end
s = 0
(3..@values[9]*6).each{ |i| s += i if sum(i) == i }
puts s
Gleicher Algorithmus wie bei 34.
Problem 31
How many different ways can £2 be made using any number of coins?
n = 200
i = 0
0.step(n,200) do |a|
a.step(n,100) do |b|
b.step(n,50) do |c|
c.step(n,20) do |d|
d.step(n,10) do |e|
e.step(n,5) do |f|
f.step(n,2) do |g|
i += 1
end
end
end
end
end
end
end
puts i
Problem 32
The product 7254 is unusual, as the identity, 39 x 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.
def dups?(a)
0.upto(a.length-2) do |i|
(i+1).upto(a.length-1) do |j|
return true if a[i] == a[j]
end
end
return false
end
hits = {}
2.upto(98) do |a|
as = a.to_s
next if dups?(as)
next if as.include?("0")
minb = (4 - as.length == 3) ? 1234 : 123
maxb = (5 - as.length == 4) ? 9876 : 987
minb.upto(maxb) do |b|
bs = b.to_s
next if bs.include?("0")
c=a*b
hits[c] = true if (as + bs + c.to_s).split("").sort.join("") == "123456789"
end
end
puts hits.map{ |k,v| k }.inject(0){ |s,k| s+k }
Idee: Durch Abschätzungen des Logarithmus zur Basis 10 und der
Gaussklammer, kann man leicht zeigen, dass
4 - length(a) <= length(b) <= 5 - length(a) gelten muss.
Das schränkt den Suchraum bereits
deutlich ein. Weiterhin müssen keine Zahlen getestet werden, die die Ziffer 0 enthalten oder die eine Ziffer
doppelt enthalten.
Problem 33
The fraction 49/98 is a curious fraction (...) 49/98 = 4/8, which is correct (...). There are exactly four non-trivial examples of this type of fraction, less than one in value, and containing two digits in the numerator and denominator. If the product of these four fractions is given in its lowest common terms, find the value of the denominator.
def gcd(a,b) return (b==0) ? a : gcd(b, a % b) end
prod = [1,1]
for a in 1..9 do
for b in a..9 do
for c in (a+1)..9 do
if (9*a+b)*c == 10*a*b then
prod[0] *= a
prod[1] *= c
end
end
end
end
puts prod[1] / gcd(prod[0], prod[1])
Winzige Optimierung: (10a+b)/(10b+c) = a/c gilt genau dann, wenn (9a+b)c = 10ab.
Problem 34
Find the sum of all numbers which are equal to the sum of the factorial of their digits.
@fac = [1,1,2,6,24,120,720,5040,40320,362880]
@table = []
def facsum(n)
return @fac[n] if n<10
return @table[n] if @table[n]
@table[n] = @fac[n%10] + facsum(n / 10)
end
s = 0
(3..@fac[9]*7).each{ |i| s += i if facsum(i) == i }
puts s
Idee: 7*9! ist eine obere Schranke, denn ab 7 Ziffern ist die größtmögliche Zahl (alle Ziffern 9) größer als die größtmögliche Summe der Fakultäten der Ziffern (Anzahl Ziffern mal 9!). Als kleine Optimierung werden noch Summen in einer Tabelle gespeichert (hat bei mir fast einen Faktor von 3 ausgemacht).
Problem 35
The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime. How many circular primes are there below one million?require 'primetool' n = 1000000 pt = PrimeTool.new(n) primes = pt.primes def rotate(s) s = "#{s[-1,1]}#{s.chop}" end count = 0 for p in primes do s = p.to_s count += 1 for i in 1..s.length-1 do s = rotate(s) if not pt.is_prime?(s.to_i) then count -= 1 break end end end puts countDiese Lösung gefällt mir nicht wirklich, sie ist viel zu langsam. Eine mögliche Optimierung: Die Dezimalentwicklung einer zirkulären Primzahl kann niemals die Ziffern 0,2,4,5,6 oder 8 enthalten.
Problem 36
Find the sum of all numbers, less than one million, which are palindromic in base 10 and base 2.
puts [*1..10**6].select{ |i| i.to_s == i.to_s.reverse and i.to_s(2) == i.to_s(2).reverse }.inject(0){ |s,x| s+x }
Ruby ist toll :-)
Problem 37
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3. Find the sum of the only eleven primes that are both truncatable from left to right and right to left. (NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes)require 'primetool' @trunc = [ {}, {} ] @hits = [] def trunc(n,i) return if n > 1000000 if PrimeTool.is_prime_trial?(n) then @trunc[i][n] = true else @trunc[i][n] = false return end for a in [1,2,3,5,7,9] do if i==0 then next if a == n.to_s[-1] trunc((n.to_s + a.to_s).to_i, 0) else next if a == n.to_s[0] trunc((a.to_s + n.to_s).to_i, 1) end end @hits << n if @trunc[0][n] and @trunc[1][n] and n%10 != 1 and n.to_s[0,1] != "1" and n > 10 end 0.upto(9) { |i| trunc(i,0); trunc(i,1) } puts @hits.inject(0){ |s,x| s+x }Sehr schöne Aufgabe mit einer sehr schnellen Lösung. Naiver Ansatz: Liste von Primzahlen erstellen (mit einem Primzahlsieb), dann dadrin die truncatables rausfischen. Leider viel zu langsam. Besserer Ansatz: Alle truncatable Primes on-the-fly generieren (mit Trial Division als Test statt dem Sieb) und dabei ausnutzen, dass diese nicht die Ziffern 0, 4, 6 und 8 enthalten können (sonst ist eine der Zahlen gerade), nicht mit 1 anfangen und nicht mit 1 enden können (1 ist nicht prim) und nicht zwei aufeinander folgende gleiche Ziffern enthalten können (sonst ist eine der Zahlen durch 11 teilbar).
Problem 39
If p is the perimeter of a right angle triangle {a,b,c}, which value, for p <= 1000, has the most solutions?
n = 1000
sols = []
1.upto(n) do |a|
a.upto(n) do |b|
c = Math.sqrt(a*a + b*b)
next unless c == c.floor
sols << [a,b,c.floor] if a+b+c <= n
end
end
sols = sols.map{ |p| p[0]+p[1]+p[2] }
count = sols.inject(Hash.new(0)){ |h,v| h[v] += 1; h }
puts sols.sort_by{ |v| count[v] }.last
Schöne Aufgabe. Erste Idee: Für alle p<=1000 alle möglichen pythagoräischen Tripel generieren. Das war allerdings viel zu langsam. Neue Idee: Alle möglichen Tripel generieren, deren Summe kleiner als 1000 ist, und dann hinterher das Maximum suchen.
Problem 38
What is the largest 1 to 9 pandigital 9-digit number that can be formed as the concatenated product of an integer with (1,2, ... , n) where n > 1?
max = 0
1.upto(9999) do |k|
digits = []
i=0
while i+=1 and digits.length < 9 do
new = (k*i).to_s.split(//)
break if new.include?("0")
break if new.uniq.length != new.length
break if digits&new != []
digits.concat new
max = [ max, digits.join("").to_i ].max if digits.length == 9
end
end
puts max
Problem 40
An irrational decimal fraction is created by concatenating the positive integers. If dn represents the nth digit of the fractional part, find the value of the following expression: d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000
digits = [*0..10**6].to_s
puts [*0..6].inject(1){ |s,x| s * digits[10**x,1].to_i }
Eigentlich hätte ich gerne eine Formel gehabt um die Ziffern direkt zu berechnen (ohne ALLE anderen auch zu speichern). Habe dann aber aufgegeben,
als ich gemerkt habe, dass es auf diese (dumme) Weise immernoch recht schnell (~1 Sekunde) ist.
Problem 41
What is the largest n-digit pandigital prime that exists?require 'primetool' def perm(k,s) 2.upto(s.length){|j| s[k%j], s[j-1], k = s[j-1], s[k%j], k / j } ; s end s = [*1..7].to_s (0..5039).map{ |i| perm(i,s).to_i }.sort.reverse.each do |n| if PrimeTool.is_prime_trial?(n) then puts n break end endIdee: Die Zahl kann weder 8-pandigital noch 9-pandigital sein, denn solche Zahlen haben eine Quersumme von 3 und sind damit selbst durch 3 teilbar, also nicht prim. (Anmerkung zum Code: 5039 = 7!-1. perm(k,s) erzeugt für jedes 0 <= k < s.length! eine eindeutige Permutation von s)
Problem 42
Using words.txt, a 16K text file containing nearly two-thousand common English words, how many are triangle words (sum of alphabetical values of letters is a triangle number)?
words = File.open('42_words.txt').read.gsub('"', '').split(/,/)
words = words.map{ |s| s.split(//).inject(0){ |s,x| s + ( x[0] - "@"[0] ) } }
t,i = [1], 1
t << t.last + (i+=1) while t.last <= words.max
puts words.select{ |w| t.include?(w) }.length
Problem 43
The number, 1406357289, is a 0 to 9 pandigital number because it is made up of each of the digits 0 to 9 in some order, but it also has a rather interesting sub-string divisibility property. Let d1 be the 1st digit, d2 be the 2nd digit, and so on. In this way, we note the following:- d2 d3 d4 = 406 is divisible by 2
- d3 d4 d5 = 063 is divisible by 3
- d4 d5 d6 = 635 is divisible by 5
- d5 d6 d7 = 357 is divisible by 7
- d6 d7 d8 = 572 is divisible by 11
- d7 d8 d9 = 728 is divisible by 13
- d8 d9 d10 = 289 is divisible by 17
digits = [0,1,2,3,4,5,6,7,8,9]
sum = 0
digits.each do |d1|
(digits - [d1]).each do |d2|
(digits - [d1, d2]).each do |d3|
((digits - [d1, d2, d3]) & [0,2,4,6,8]).each do |d4|
(digits - [d1, d2, d3, d4]).each do |d5|
next if (d3+d4+d5) % 3 != 0
((digits - [d1,d2,d3,d4,d5]) & [0,5]).each do |d6|
(digits - [d1,d2,d3,d4,d5,d6]).each do |d7|
next if (100*d5 + 10*d6 + d7) % 7 != 0
(digits - [d1,d2,d3,d4,d5,d6,d7]).each do |d8|
next if (100*d6 + 10*d7 + d8) % 11 != 0
(digits - [d1,d2,d3,d4,d5,d6,d7,d8]).each do |d9|
next if (100*d7 + 10*d8 + d9) % 13 != 0
(digits - [d1,d2,d3,d4,d5,d6,d7,d8,d9]).each do |d10|
next if (100*d8 + 10*d9 + d10) % 17 != 0
sum += [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10].join("").to_i
end
end
end
end
end
end
end
end
end
end
puts sum
Ziemlich straight-forward und recht schnell.
Problem 44
Find the pair of pentagonal numbers, Pj and Pk, for which their sum and difference is pentagonal and D =|Pk - Pj| is minimised; what is the value of D?
pentas = {}
p = k = 0
while true do
p += 3*k + 1
k += 1
pentas.each_key do |q|
if pentas[p-q] and pentas[p-q-q] then
puts "#{p-2*q}"
exit
end
end
pentas[p] = true
end
Idee: Abstand zwischen Pk und Pk+1 ist 3k+1.
Problem 45
Find the next triangle number (> 40755) that is also pentagonal and hexagonal.def H(n) n*(2*n-1) end def penta?(x) k = Math.sqrt(24*x+1).floor return ( k**2 == (24*x+1) and (k+1)%6 == 0 ) end i=143 while true do i += 1 break if penta?(H(i)) end puts H(i)Sehr schöne Aufgabe! Idee: Jede hexagonale Zahl ist eine Dreieckszahl, also können die Dreieckszahlen komplett ignoriert werden. Ausserdem ist eine natürliche Zahl n genau dann pentagonal, wenn sqrt(24n+1)+1 eine durch 6 teilbare natürliche Zahl ist.
Problem 46
What is the smallest odd composite that cannot be written as the sum of a prime and twice a square?require 'primetool' pt = PrimeTool.new(10000) k=35 while k += 2 do hit = false pt.primes[1..-1].each do |p| break if p > k q = ( k - p ) / 2 if Math.sqrt(q).floor ** 2 == q then hit = true break end end unless hit puts k break end end
Problem 47
Find the first four consecutive integers to have four distinct primes factors (each). What is the first of these numbers?require 'primetool' pt = PrimeTool.new(700) factors = {} k = 2*3*5*7 factors[k-1] = factors[k-2] = factors[k-3] = [] while true do factors[k] = [] m = k pt.primes.each do |p| break if p > m if m % p == 0 then factors[k] << p m /= p while m%p == 0 if factors[m] factors[k].concat factors[m] break end break if factors[k].length > 4 end end if factors[k].length == 4 and factors[k-1].length == 4 and factors[k-2].length == 4 and factors[k-3].length == 4 then puts k-3 break end k += 1 end
Problem 48
Find the last ten digits of the series, 11 + 22 + 33 + ... + 10001000.
puts [*1..1000].inject(0){ |s,i| s + ( (i**i) % (10**10) ) } % (10**10)
Idee: In jedem Schritt nur die letzten 10 Ziffern betrachten.
Problem 49
The arithmetic sequence, 1487, 4817, 8147, in which each of the terms increases by 3330, is unusual in two ways: (i) each of the three terms are prime, and, (ii) each of the 4-digit numbers are permutations of one another. (...) There is one other 4-digit increasing sequence. What 12-digit number do you form by concatenating the three terms in this sequence?require 'primetool' pt = PrimeTool.new(9999) # 1009 ist die 169. Primzahl und die erste, die vierstellig ist i = 169 j = i+1 while true do p = [ pt.prime(i), pt.prime(j), nil ] if p[1].nil? then i,j = i+1, i+2 next end p[2] = 2 * p[1] - p[0] j += 1 next unless pt.is_prime?(p[2]) next unless p[0].to_s.split(//).sort == p[1].to_s.split(//).sort next unless p[0].to_s.split(//).sort == p[2].to_s.split(//).sort next unless p[1].to_s.split(//).sort == p[2].to_s.split(//).sort next if p[0] == 1487 puts p.to_s break endSchöne Aufgabe!
Problem 50
Which prime, below one-million, can be written as the sum of the most consecutive primes?require 'primetool' n = 1000000 p = PrimeTool.new(n) primes = p.primes maxp = maxl = 0 for i in 0..(primes.length-1) do sum = primes[i] list = [ sum ] for j in 1..((primes.length-1)-i) do sum += primes[i+j] break if sum >= n list << primes[i+j] if p.is_prime?(sum) then if list.length > maxl then maxp = sum maxl = list.length end end end end puts maxp
Problem 52
Find the smallest positive integer, x, such that 2x, 3x, 4x, 5x, and 6x, contain the same digits.def digits(n) n.to_s.split(//).sort end i=0 while true do i += 1 digits = digits(i) next if digits(2*i) != digits next if digits(3*i) != digits next if digits(4*i) != digits next if digits(5*i) != digits next if digits(6*i) != digits puts i exit endEditor auf, Code runtergeschrieben, Editor zu, gestartet, tut.
Problem 53
How many, not necessarily distinct, values of nCr, for 1 <= n <= 100, are greater than one-million?
max = 100
count = 0
binomi = [ [1] ]
0.upto(max-1) do |n|
binomi[n] = []
0.upto(n) do |r|
binomi[n][r] = (n==r) ? 1 : binomi[n][r] = binomi[n-1][r-1] + binomi[n-1][r]
count += 1 if binomi[n][r] > 1000000
end
end
puts count
Idee: Dynamische Programmierung und Rekursionsformel benutzen.
Problem 54
The file poker.txt contains one-thousand random hands dealt to two players. Each line of the file contains ten cards (separated by a single space): the first five are Player 1's cards and the last five are Player 2's cards. How many hands does Player 1 win?
def parsehand(s)
s = s.split(/ /)
s.each_index do |i|
s[i] = s[i].split(//)
s[i][0] = s[i][0].gsub("T","10").gsub("J","11").gsub("Q","12").gsub("K","13").gsub("A","14").to_i
s = s.sort_by{ |a| a[0] }
end
s
end
def onepair?(h)
return h[0][0] if h[0][0] == h[1][0]
return h[1][0] if h[1][0] == h[2][0]
return h[2][0] if h[2][0] == h[3][0]
return h[3][0] if h[3][0] == h[4][0]
return nil
end
def twopairs?(h)
( h[0][0] == h[1][0] and h[2][0] == h[3][0] ) or \
( h[0][0] == h[1][0] and h[3][0] == h[4][0] ) or \
( h[1][0] == h[2][0] and h[3][0] == h[4][0] )
end
def triplet?(h)
( h[0][0] == h[1][0] and h[1][0] == h[2][0] ) or \
( h[1][0] == h[2][0] and h[2][0] == h[3][0] ) or \
( h[2][0] == h[3][0] and h[3][0] == h[4][0] )
end
def straight?(h)
h[0][0] + 1 == h[1][0] and \
h[1][0] + 1 == h[2][0] and \
h[2][0] + 1 == h[3][0] and \
h[3][0] + 1 == h[4][0]
end
def flush?(h)
h[0][1] == h[1][1] and h[1][1] == h[2][1] and h[2][1] == h[3][1] and h[3][1] == h[4][1]
end
def fullhouse?(h)
( h[0][0] == h[1][0] and h[1][0] == h[2][0] and h[3][0] == h[4][0] ) or \
( h[0][0] == h[1][0] and h[2][0] == h[3][0] and h[3][0] == h[4][0] )
end
def quadruplet?(h)
( h[0][0] == h[1][0] and h[1][0] == h[2][0] and h[2][0] == h[3][0] ) or \
( h[1][0] == h[2][0] and h[2][0] == h[3][0] and h[3][0] == h[4][0] )
end
def straightflush?(h)
straight?(h) and flush?(h)
end
def royalflush?(h)
straightflush?(h) and h[0][0] == 10
end
def rank(h)
return 9 if royalflush?(h)
return 8 if straightflush?(h)
return 7 if quadruplet?(h)
return 6 if fullhouse?(h)
return 5 if flush?(h)
return 4 if straight?(h)
return 3 if triplet?(h)
return 2 if twopairs?(h)
return 1 if onepair?(h)
return 0
end
def winner(g,h)
if rank(g) < rank(h) then
return 2
elsif rank(g) > rank(h) then
return 1
end
if rank(g) == 0 then
return g[4][0] > h[4][0] ? 1 : 2
end
if rank(g) == 1 then
if onepair?(g) > onepair?(h) then
return 1
elsif onepair?(g) < onepair?(h) then
return 2
else
return g[4][0] > h[4][0] ? 1 : 0
end
end
end
puts File.open("54_poker.txt").readlines.map{ |l| [ l[0,14], l[15,14] ] }.select{ |h|
winner(parsehand(h[0]), parsehand(h[1])) == 1
}.length
Lustige Aufgabe... Etwas lange Lösung.
Problem 55
If we take 47, reverse and add, 47 + 74 = 121, which is palindromic. A number that never forms a palindrome through the reverse and add process is called a Lychrel number. (...) every number below ten-thousand, it will either (i) become a palindrome in less than fifty iterations, or, (ii) no one, with all the computing power that exists, has managed so far to map it to a palindrome. How many Lychrel numbers are there below ten-thousand?
def lychrel?(n,i)
return true if i == 50
return false if n.to_s == n.to_s.reverse and i>0
lychrel?(n + n.to_s.reverse.to_i, i+1)
end
puts (0..10**4).select{ |i| lychrel?(i,0) }.length
Problem 56
Considering natural numbers of the form, ab, where a, b < 100, what is the maximum digital sum?
n = 100
def qs(n)
ret = 0
while n > 0 do
ret += n%10
n/=10
end
return ret
end
max=0
(1..(n-1)).each{ |a| (1..(n-1)).each{ |b| max = [max,qs(a**b)].max } }
puts max
Problem 57
In the first one-thousand continued fraction expansions of sqrt(2), how many fractions contain a numerator with more digits than denominator?n = 1000 c,a,b = 0,1,1 1.upto(n) do b, a = a+b, 2*b+a c+=1 if a.to_s.length > b.to_s.length end puts cEtwas tricky drauf zu kommen, aber im Nachhinein relativ simpel.
Problem 58
What is the side length of the square spiral for which the ratio of primes along both diagonals first falls below 10%?require 'primetool' pt = PrimeTool.new(50000) d = l = last = 1 primes = 0 while l += 2 do [ last + (l-1), last + 2*(l-1), last + 3*(l-1) ].each{ |n| primes += 1 if pt.is_prime_trial_with_sieve?(n) } last += 4*(l-1) d += 4 break if 10*primes < d end puts lEigentlich eine leichte Aufgabe, aber trotzdem in Ruby recht langsam. Optimierungen, die mir eingefallen sind: Zahlenreihe durch Additionen statt Multiplikationen erzeugen; Letzte Zahl ist ein Quadrat (also nie prim); Nur ungerade Seitenlängen betrachten; ...
Problem 59
A (...) encryption method is to take a text file, (...), then XOR each byte with a given value, taken from a secret key. (...) the encryption key consists of three lower case characters. Using cipher1.txt (...), a file containing the encrypted ASCII codes, and the knowledge that the plain text must contain common English words, decrypt the message and find the sum of the ASCII values in the original text.
cipher = File.open("59_cipher1.txt").read.chomp.split(/,/).map{|c| c.to_i }
keydigs = [*"a"[0].."z"[0]]
keydigs.each do |a|
keydigs.each do |b|
keydigs.each do |c|
key = [a,b,c]
sum = 0
catch :break do
cipher.each_index do |i|
sum += s = key[i % 3] ^ cipher[i]
throw :break if s < 20 or (s >= 35 and s <= 38) or s > 122
end
puts sum
exit
end
end
end
end
Nettes Problem. Idee: Mögliche Keys bruteforcen und die Ciphers, deren zugehöriger Plaintext Sonderzeichen und nicht-darstellbare ASCII Zeichen enthält, ignorieren.
Problem 62
Find the smallest cube for which exactly five permutations of its digits are cube.
perms = 5
res = {}
digits = 1
i = 0
while i += 1 and c = i**3 do
if c > 10**digits then
break if ( r = res.values.select{ |v| v.length == perms }.map{ |v| v.min } ) != []
digits += 1
end
nf = c.to_s.split("").sort.to_s
res[nf] = res[nf].nil? ? [ c ] : (res[nf] << c).sort
end
puts r.min
Nicht die schönste Lösung, aber blitzschnell. Idee: Alle Kubikzahlen generieren und
jedesmal wenn die Ziffernlänge sich erhöht hat, nachgucken ob wir bereits einen Treffer haben.
Die Rechnungen werden in einem Hash gespeichert, dessen Key die "sortierte Zahl" ist (denn das
ist offensichtlich eine Normalform für die Bahnen der Zahl unter Permutationen).
Problem 63
How many n-digit positive integers exist which are also an nth power?i = j = 1 n = 0 while n += 1 and i < 10 do l = (i**n).to_s.length j += 1 if l == n i, n = i+1, 0 if l < n end puts j-1Tipp: Man rechnet leicht nach, dass die Basis nicht größer als 9 sein darf.
Problem 65
Find the sum of digits in the numerator of the 100th convergent of the continued fraction for e.
require 'rational'
n = 100
exp = [ 2 ]
2.step(n,2){ |i| exp.concat [ 1, i, 1] }
def exp_to_rat(exp) Rational(exp[0],1) + ((exp.length == 1) ? 0 : Rational(1, exp_to_rat(exp[1..-1]))) end
puts exp_to_rat(exp[0..n-1]).numerator.to_s.split(//).inject(0){ |s,x| s + x.to_i }
Gähn. :-)
Problem 66
Consider quadratic Diophantine equations of the form: x2 - Dy2 = 1. Find the value of D <= 1000 in minimal solutions of x for which the largest value of x is obtained.
require 'rational'
def fu(s)
m = [ 0 ]
d = [ 1 ]
a = [ Math.sqrt(s).to_i ]
i = 0
while i += 1 do
m[i] = d[i-1] * a[i-1] - m[i-1]
d[i] = (s - m[i] ** 2) / d[i-1]
a[i] = (( a[0] + m[i] ) / d[i] ).to_i
if i == 2 then
lastlast = Rational(a[0],1)
last = Rational(a[1] * a[0] + 1, a[1])
end
if i >= 2 then
x = a[i] * last.numerator + lastlast.numerator
y = a[i] * last.denominator + lastlast.denominator
if x**2 - s * (y**2) == 1 then
return Rational(x,y)
break
end
lastlast = last
last = Rational(x,y)
end
end
end
maxval = 0
maxi = 0
1.upto(1000) do |s|
next if Math.sqrt(s).to_i ** 2 == s
v = fu(s).denominator
if v > maxval then
maxval = v
maxi = s
end
end
puts maxi
Eine interessante Aufgabe mit viel Theorie dahinter, die mich einige Zeit gekostet hat.
Glücklicherweise habe ich vor kurzem eine Vorlesung über algebraische Zahlentheorie gehört
und habe daher erkannt, dass man hier die sogenannte Grundeinheiten im Ganzheitsring
des quadratischen Zahlkörpers Q(sqrt(D)) bestimmen soll. Habe mich dann etwas
schlau gemacht und herausgefunden, dass die Lösung des Problems in dem generieren der
Kettenbruchapproximationen liegt (sqrt(D) ist irrational falls D kein Quadrat ist und hat daher
eine unendliche Kettenbruchentwicklung). Ein paar Links als Anlaufpunkt:
Infinite continued fractions,
Continued fraction expansion of squares,
Pell Gleichung.
Problem 67
Find the maximum total from top to bottom in triangle.txt, a 15K text file containing a triangle with one-hundred rows.
triangle = []
f = File.open("67_triangle.txt")
while l = f.gets do triangle << l.split(/ /) end
f.close
triangle.each_index{ |i| triangle[i].each_index{ |j| triangle[i][j] = triangle[i][j].to_i }}
(triangle.length-2).downto(0) { |i|
for j in 0..(triangle[i].length-1) do
triangle[i][j] += [triangle[i+1][j], triangle[i+1][j+1]].max
end
}
puts triangle[0][0]
Siehe Problem 18.
Problem 69
Find the value of n <= 1,000,000 for which n/phi(n) is a maximum.require 'primetool' max = 10**6 n = 1 1.upto(max) do |p| next unless PrimeTool.is_prime_trial?(p) break if (n*p) >= max n *= p end puts nErst etwas Brute-Force probiert, dann gemerkt, dass man die Aufgabe recht einfach (sogar ohne Computer) lösen kann. Damit n/phi(n) gross wird, sollte phi(n) klein sein. Bekanntlich ist phi(p)=p-1 und phi zahlentheoretisch. Die korrekte Lösung ist daher phi(2*3*5*7*11*13*17) (Produkt der ersten k Primzahlen, so dass das Produkt kleiner als die gegebene Schranke ist).
Problem 71
By listing the set of reduced proper fractions n/d for d <= 1,000,000 in ascending order of size, find the numerator of the fraction immediately to the left of 3/7.
max = 10**6
a = nil
def ggT(a,b) (b == 0) ? a : ggT(b, a % b) end
max.downto(1) do |n|
if (a = 3*n-1) % 7 == 0 then
a /= 7
break if ggT(a,n) == 1
end
end
puts a
Lustigerweise habe ich mich genau in dem moment, in dem ich das Problem zum ersten mal gelesen habe,
zufälligerweise mit genau diesem Thema beschäftigt (in der Vorlesung
Algebraische Zahlentheorie II
von Herrn Prof. Krieg an der RWTH-Aachen) und wusste daher, dass
für zwei aufeinanderfolgende Farey-Brüche
a/b und c/d die Beziehung bc-ad=1 gilt. Daher muss für
den gesuchten Bruch a/b die Beziehung a = (3b-1)/7 gelten.
Problem 72
How many elements would be contained in the set of reduced proper fractions n/d for d <= 1,000,000?require 'primetool' max = 10**6 phi = Array.new(max+1){ |i| i } pt = PrimeTool.new(max) pt.primes.each do |i| phi[i] = i-1 j=1 while j += 1 and (k = i*j) <= max do phi[k] -= phi[k]/i end end puts phi[2..-1].inject(0){ |s,k| s+k }Wenn man ein bisschen etwas über Farey-Brüche weiss, dann ist klar, dass hier die Summe über die Werte der Phi-Funktion gesucht ist. Habe zuerst ewig lange irgendwelche optimierten Brute-Force Varianten ausprobiert (die aber schon für deutlich kleinere Werte von d extrem langsam waren), bis ich zufällig im Netz eine klevere Methode gefunden habe, um eine Wertetabelle der Phi-Funktion aufzustellen (die ganz ähnlich funktioniert wie ein Primzahlsieb und viel schneller ist als der naive Ansatz über den euklidischen Algorithmus).
Problem 76
How many different ways can one hundred be written as a sum of at least two positive integers?n = 100 @cache = Array.new(n+1) @cache.each_index do |i| @cache[i] = [] end def p(k,n) return 0 if k>n return 1 if k==n @cache[k][n] ? @cache[k][n] : ( @cache[k][n] = p(k+1,n) + p(k,n-k) ) end puts p(1,n)-1Jeder der schonmal etwas Kombinatorik betrieben hat weiss, dass es hier um die sogenannte Partitionsfunktion geht. Eine explizite Darstellung ist mir nicht bekannt, aber man kann sie relativ leicht rekursiv beschreiben und mit einer Memo Tabelle geht das sogar halbwegs flott. Links: Wolfram MathWorld, Sloans.
Problem 79
A common security method used for online banking is to ask the user for three random characters from a passcode. The text file, keylog.txt, contains fifty successful login attempts. Given that the three characters are always asked for in order, analyse the file so as to determine the shortest possible secret passcode of unknown length.
tsort = File.popen("tsort", "r+")
data = File.open("79_keylog.txt").readlines.sort.uniq.map do |v|
v = v.split(//); tsort.puts "#{v[0]} #{v[1]} #{v[0]} #{v[2]} #{v[1]} #{v[2]}"
end
tsort.close_write
puts tsort.readlines.map{ |l| l.chomp }.join("")
An dieser Aufgabe bin ich lange verzweifelt bis mein Kollege Johannes
die Aufgabe mit Stift und Papier in weniger als einer Minute gelöst hat. Das Prinzip ist natürlich
total simpel, man stellt die Daten als gerichteten Graphen dar und macht eine
Topologische Sortierung.
Problem 92
How many numbers below 10.000.000 are not happy?
@happymemo = []
@qsmemo = []
@happymemo[567] = nil
@happymemo[1] = true
@happymemo[89] = false
def qs(n)
@qsmemo[n].nil? ? ( @qsmemo[n] = (n<10) ? n**2 : ( (n%10)**2 + qs(n/10) ) ) : @qsmemo[n]
end
def happy(n)
(n>567) ? @happymemo[qs(n)] : ( @happymemo[n].nil? ? ( @happymemo[n] = happy(qs(n)) ) : @happymemo[n] )
end
puts [*2..10**7].select{ |n| !happy(n) }.length
Schöne Aufgabe eigentlich. Leider ist meine Lösung extrem langsam. Im wesentlichen Brute Force mit zwei
Memo-Tables. Winzige Optimierung: Die Tabelle muss
nur bis maximal 567 gehen, denn das ist die größtmögliche Zahl, die erreicht werden kann.
Problem 97
In 2004 there was found a massive non-Mersenne prime which contains 2,357,207 digits: 28433 * 27830457+1. Find the last ten digits of this prime number.
ret = 1
1.upto(783){ # 7830457 / 10000
ret *= 2596709376 # (2^10000) % (10^10)
ret %= (10**10)
}
ret *= (2**457) # 7830457 % 10000
puts ( 28433 * (ret % (10**10)) + 1 ) % ( 10 ** 10 )
Schöne Aufgabe! Idee: Große Schritte machen und in jedem schon nur mit den letzten 10 Stellen rechnen.
Problem 99
Using base_exp.txt, a 22K text file containing one thousand lines with a base/exponent pair on each line, determine which line number has the greatest numerical value.
f = File.open("99_base_exp.txt")
d = []
n = 0
while l = f.gets do
d << [ n += 1, l.split(/,/).map{ |c| c.to_i } ].flatten
end
puts d.sort_by{ |n,a,b| (b * Math.log(a)) }.last[0]
Sehr einfach. Vergleiche die Logarithmen statt
den Werten...
Problem 104
Given that Fk is the first Fibonacci number for which the first nine digits AND the last nine digits are 1-9 pandigital (contain all the digits 1 to 9, but not necessarily in order), find k.
def pandigital?(n)
return false if n < 10**8
return n.to_s.split(//).sort.map{ |i| i.to_i } == [*1..9]
end
i,a,b,x,y = 1,1,1,1,1
while true do
if pandigital?(a) and pandigital?(x.to_s[0..8].to_i) then
puts i
exit
end
a, b = b % (10**9), (a+b) % (10**9)
x, y = y, x+y
if y >= 10**18 then x /= 10; y /= 10 end
i+=1
end
Eine recht schwere Aufgabe. Das gesuchte k ist relativ gross und die zugehörige k-te
Fibonacci Zahl hat mehrere tausend Stellen. Idee: Erzeuge nicht die Fibonacci Folge sondern
die Folge der letzten und vorderen 9 Ziffern jedes Folgengliedes.
Problem 119
The number 512 is interesting because it is equal to the sum of its digits raised to some power: 5 + 1 + 2 = 8, and 83 = 512. Another example of a number with this property is 614656 = 284. We shall define an to be the n-th term of this sequence and insist that a number must contain at least two digits to have a sum. You are given that a2 = 512 and a10 = 614656. Find a30.
def qs(n) n < 10 ? n : (n % 10) + qs(n/10) end
a = []
1.upto(100) do |b|
a << [b, b]
10.times do a << [b, a.last[1] * b] end
end
puts a.select{ |n| n[0] == qs(n[1]) }.select{ |n| n[1] >= 10 }.map{ |n| n[1] }.sort[29]
Erste Idee: Zahlen der Reihe nach durchlaufen und dann die passende Potenz dazu finden (viel zu langsam).
Zweite Idee: Testen ob der Logarithmus zur Quersumme als Basis ganzzahlig ist (viel zu langsam).
Dritte (gute) Idee: Alle Potenzen generieren und dann die rausfischen, die die gewünschte Eigenschaft
haben (sehr schnell :-)).
Problem 120
Let r be the remainder when (a-1)n + (a+1)n is divided by a2. (...) as n varies, so too will r, but for a = 7 it turns out that rmax = 42. For 3 <= a <= 1000, find the sum of all the rmax.
puts [*3..1000].inject(0){ |s,a| s += 2 * (a - 2 + (a%2))/2 * a }
Recht einfach, wenn man Aufgabe 123 vorher schon gemacht hat.
Problem 123
Let pn be the n-th prime (...) and let r be the remainder when (pn-1)n + (pn+1)n is divided by pn2. Find the least value of n for which the remainder first exceeds 1010.require 'primetool' @pt = PrimeTool.new(5 * 10**5) i = 7037 break if 2*i*@pt.primes[i-1] > 10**10 while i += 2 puts iNette Aufgabe. Mit dem Binomischen Lehrsatz lassen sich die beiden Potenzen ausschreiben, anschließend kann man zusammenfassen und man sieht, dass modulo pn2 fast alle Summanden gleich Null sind und sich der ganze Term zu 2 * n * pn vereinfacht, falls n ungerade ist, und zu 2, falls n gerade ist.
Problem 125
Find the sum of all the numbers less than 108 that are both palindromic and can be written as the sum of consecutive squares.
max = 10 ** 8
k = 0
hits = []
while k += 1 and n = k do
while n += 1 do
m = ( (n-k+1) * (2 * ( k*k + n*(k+n) ) + n-k) ) / 6
break if m >= max
hits << m if m.to_s == m.to_s.reverse
end
break if n == k+2
end
puts hits.uniq.inject(0){ |s,x| s+x }
Aus der bekannten
Formel für die Summe der ersten n Quadrate, kann man leicht eine Formel ableiten für
die Summe der Quadrate von k bis n. Vorsicht: Die Darstellung einer Zahl als
Summe aufeinanderfolgender Quadrate ist nicht eindeutig (d.h. man muss aufpassen,
dass man keine Zahl doppelt zählt).
Problem 131
There are some prime values, p, for which there exists a positive integer, n, such that the expression n3 + p * n2 is a perfect cube. How many primes below one million have this remarkable property?require 'primetool' n = 0 values = [] break if values.last > 10**6 while n+=1 and values << (n+1)**3 - n**3 puts values[0..-2].select{ |p| PrimeTool.is_prime_trial?(p) }.lengthSehr schöne Aufgabe. Der Brute-Force Ansatz lässt sich zwar etwas optimieren, aber dauert trotzdem noch mehrere Minuten. Schöner: n2 * (n + p) ist aufjedenfall eine Kubikzahl, wenn sowohl n als auch n+p welche sind (etwa n = m3). Wenn dies der Fall ist, ist p die Differenz zweier Kubikzahlen (p = (n+p) - n). Die Differenz zweier Kubikzahlen faktorisiert aber zu a3 - b3 = (a-b)(a2 + ab + b2), d.h. es muss a=b+1 gelten (also p = (m+1)3 - m3). Die Primzahl p ist also die Differenz zweier aufeinander folgender Kubikzahlen (solche Primzahlen nennt man übrigens Cuban Primes).
Problem 197
Given is the function f(x) = [230.403243784 - x2] * 10-9, the sequence un is defined by u0 = -1 and un+1 = f(un). Find un + un+1 for n = 1012. Give your answer with 9 digits after the decimal point.
def f(x) (2 ** (30.403243784 - (x*x))).floor / (10.0 ** 9) end
last = -1
1.upto(1000){ |n| last = f(last) }
puts last+f(last)
Sehr langweilige Aufgabe.. Wie viele andere vermutlich auch hatte ich eine Art von fraktalem und "chaotischem"
Verhalten erwartet. Man sieht aber (durch ausprobieren) leicht, dass die Folge recht schnell (ab ca. 500 Iterationen)
um zwei Werte oszilliert (und die Summe von aufeinanderfolgenden Folgengliedern damit konvergiert (und die ersten
9 Stellen sich nichtmehr ändern)).
Problem 203
Find the sum of the distinct squarefree numbers in the first 51 rows of Pascal's triangle.
rows = 51
def squarefree?(n)
d = 1
while d += 1 do
return true if d > n
if n % d == 0 then
n /= d
return false if n%d == 0
end
end
end
binomi = [ [1] ]
0.upto(rows-1) do |n|
binomi[n] = []
0.upto(n) do |r|
binomi[n][r] = (n==r || r == 0) ? 1 : ( binomi[n-1][r-1] + binomi[n-1][r] )
end
end
puts binomi.flatten.uniq.select{ |k| squarefree?(k) }.inject(0){ |s,k| s+k }
Viel zu einfach für ein Level 5 Problem.
Problem 206
Find the unique positive integer whose square has the form 1_2_3_4_5_6_7_8_9_0, where each "_" is a single digit.max = Math.sqrt(192939495969798990 / 10).ceil while (max*max).to_s !~ /^1\d2\d3\d4\d5\d6\d7\d8\d9$/ do max -= 2 end puts max*10Schöne Aufgabe, einfache Lösung. Die Zahl endet mit 0, ist also durch 10 teilbar. Da es sich um ein Quadrat handelt (und 10 quadratfrei ist) muss auch die Wurzel durch 10 teilbar sein, also die Zahl selbst sogar durch 100, d.h. auch die vorletzte Ziffer muss eine 0 sein, die letzten zwei Ziffern können also ignoriert werden, damit ist die letzte relevante Ziffer eine 9. Eine Zahl, deren Quadrat als letzte Ziffer eine 9 hat, muss als letzte Ziffer eine 3 oder eine 7 haben (sieht man an der Rechnung modulo 10), in jedem Fall ist unsere gesuchte Wurzel also ungerade. Die größtmögliche Wurzel ist also 138902663. Von hier aus testen wir abwärts in Zweierschritten, ob wir eine Lösung gefunden haben (und multiplizieren diese anschließend mit 10).
Tools
Um oft auftauchenden Code leicht wiederverwenden zu können, habe ich einige Teile in extra Dateien ausgelagert.
primetool.rb
Ein primitives Primzahlsieb.
class PrimeTool
def initialize(n)
@primes = []
@marked = [*0..n]
@marked[0] = @marked[1] = nil
limit = Math.sqrt(n).floor
@marked.each do |i|
next unless i
break if i > limit
(i*i).step(n,i) { |m| @marked[m] = nil }
end
@primes = @marked.select{ |p| p != nil }
return self
end
def is_prime?(n)
return ( @marked[n] != nil )
end
def self.is_prime_trial?(n)
return (n==2) if (n%2==0)
d = 3
while d*d <= n do
return false if (n%d==0)
d += 2
end
return true
end
def is_prime_trial_with_sieve?(n)
return is_prime?(n) if n < @primes.last
primes.each do |p|
return false if n%p == 0
end
return true
end
def prime(i)
return @primes[i-1]
end
def primes
return @primes
end
end