Compare commits
39 Commits
101f5d139e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f4dc0e1739 | |||
| 452dda6fc9 | |||
| b889c12ae7 | |||
| 75b4398c90 | |||
| f00afc0a1b | |||
| f1fee73db4 | |||
| e3919ff56b | |||
| 1159fe0747 | |||
| 8fdec345d9 | |||
| cd2e933afe | |||
| a07f34075b | |||
| 5ce2c5bcbf | |||
| 0c1280ce91 | |||
| e9873eaa2f | |||
| ceca539c70 | |||
| a0c906bd58 | |||
| c3f24f445e | |||
| 3d35bcb76d | |||
| fce3304078 | |||
| 0e82dac7ca | |||
| 5c8b4b1de7 | |||
| 1f09714d46 | |||
| e0be0b71cb | |||
| 8214d9f424 | |||
| 2a181cdbd1 | |||
| 642432cef8 | |||
| 06c46a3e26 | |||
| 1dbadab602 | |||
| 09f7e27c16 | |||
| 927cd2011b | |||
| 0509ee4f7a | |||
| a410add121 | |||
| 303eae42c9 | |||
| dd89390a04 | |||
| 9f54759c28 | |||
| 389406fc16 | |||
| a0a8fcda7d | |||
| 3e6add8dd0 | |||
| c9b5f106f4 |
@@ -1,4 +1,3 @@
|
|||||||
#
|
|
||||||
def choose(xs, n):
|
def choose(xs, n):
|
||||||
"""
|
"""
|
||||||
Computes r choose n, in other words choose n from xs.
|
Computes r choose n, in other words choose n from xs.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
|
from lib_misc import proper_divisors
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
|
||||||
def get_distinct_solutions(n):
|
def get_distinct_solutions(n):
|
||||||
@@ -16,11 +18,16 @@ def get_distinct_solutions(n):
|
|||||||
return n_distinct
|
return n_distinct
|
||||||
|
|
||||||
|
|
||||||
|
def get_distinct_solutions2(n):
|
||||||
|
ds = proper_divisors(n * n)
|
||||||
|
return ceil((len(ds) + 1) / 2)
|
||||||
|
|
||||||
|
|
||||||
def euler_108():
|
def euler_108():
|
||||||
d_max, n_prev = 0, 0
|
d_max, n_prev = 0, 0
|
||||||
# I arrived at the starting values empirically by observing the deltas.
|
# I arrived at the starting values empirically by observing the deltas.
|
||||||
for n in range(1260, 1000000, 420):
|
for n in range(1260, 1000000, 420):
|
||||||
d = get_distinct_solutions(n)
|
d = get_distinct_solutions2(n)
|
||||||
if d > d_max:
|
if d > d_max:
|
||||||
# print("n={} d={} delta={}".format(n, d, n - n_prev))
|
# print("n={} d={} delta={}".format(n, d, n - n_prev))
|
||||||
n_prev = n
|
n_prev = n
|
||||||
|
|||||||
75
python/e110.py
Normal file
75
python/e110.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
from lib_misc import get_item_counts
|
||||||
|
from lib_prime import primes
|
||||||
|
|
||||||
|
|
||||||
|
def divisors(counts):
|
||||||
|
r = 1
|
||||||
|
for c in counts:
|
||||||
|
r *= (c + 1)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def tau(factors):
|
||||||
|
orig_factors = factors
|
||||||
|
factors = factors + factors
|
||||||
|
counts = get_item_counts(factors)
|
||||||
|
r = divisors(counts.values())
|
||||||
|
p = 1
|
||||||
|
for f in orig_factors:
|
||||||
|
p *= f
|
||||||
|
return r, p
|
||||||
|
|
||||||
|
|
||||||
|
def counters(digits, max_digit):
|
||||||
|
def incrementing_counters(curr, left, max_digit, result):
|
||||||
|
if left == 0:
|
||||||
|
result.append(curr)
|
||||||
|
return
|
||||||
|
start = 1 if not curr else curr[-1]
|
||||||
|
for i in range(start, max_digit + 1):
|
||||||
|
incrementing_counters(curr + [i], left - 1, max_digit, result)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
incrementing_counters([], digits, max_digit, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def euler_110():
|
||||||
|
target = 1000
|
||||||
|
target = 4 * 10**6
|
||||||
|
threshold = (target * 2) - 1
|
||||||
|
psupper = primes(1000)
|
||||||
|
|
||||||
|
lowest_distinct = 0
|
||||||
|
lowest_number = 0
|
||||||
|
|
||||||
|
# find upper bound
|
||||||
|
for i in range(len(psupper)):
|
||||||
|
distinct, number = tau(psupper[:i])
|
||||||
|
if distinct > threshold:
|
||||||
|
# print(lowest_distinct, number)
|
||||||
|
lowest_distinct = distinct
|
||||||
|
lowest_number = number
|
||||||
|
psupper = psupper[:i]
|
||||||
|
|
||||||
|
for j in range(1, len(psupper)):
|
||||||
|
ps = psupper[:-j]
|
||||||
|
for prime_counts in counters(len(ps), 5):
|
||||||
|
prime_counts.reverse()
|
||||||
|
nps = []
|
||||||
|
i = 0
|
||||||
|
for i in range(len(prime_counts)):
|
||||||
|
nps += [ps[i]] * prime_counts[i]
|
||||||
|
nps += ps[i + 1:]
|
||||||
|
distinct, number = tau(nps)
|
||||||
|
if distinct > threshold and distinct < lowest_distinct:
|
||||||
|
lowest_distinct = distinct
|
||||||
|
lowest_number = number
|
||||||
|
# print(lowest_distinct, lowest_number)
|
||||||
|
return lowest_number
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_110()
|
||||||
|
print("e110.py: " + str(solution))
|
||||||
|
assert(solution == 9350130049860600)
|
||||||
27
python/e122.py
Normal file
27
python/e122.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
def euler_122():
|
||||||
|
upper = 201
|
||||||
|
m_k = {k: 0 for k in range(2, upper)}
|
||||||
|
sets = [[1]]
|
||||||
|
for _ in range(11):
|
||||||
|
new_sets = []
|
||||||
|
for s in sets:
|
||||||
|
for i in range(len(s)):
|
||||||
|
new_elem = s[i] + s[-1]
|
||||||
|
if new_elem in m_k and m_k[new_elem] == 0:
|
||||||
|
m_k[new_elem] = len(s)
|
||||||
|
new_sets.append(s + [new_elem])
|
||||||
|
|
||||||
|
# For better performance, we would have to prune here.
|
||||||
|
sets = new_sets
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for k in range(2, upper):
|
||||||
|
assert m_k[k] != 0
|
||||||
|
r += m_k[k]
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_122()
|
||||||
|
print("e122.py: " + str(solution))
|
||||||
|
assert solution == 1582
|
||||||
24
python/e124.py
Normal file
24
python/e124.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from lib_prime import prime_factors
|
||||||
|
|
||||||
|
|
||||||
|
def radical(n: int) -> int:
|
||||||
|
fs = prime_factors(n)
|
||||||
|
r = 1
|
||||||
|
for f in set(fs):
|
||||||
|
r *= f
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_124():
|
||||||
|
assert radical(504) == 42
|
||||||
|
xs = []
|
||||||
|
for n in range(1, 100001):
|
||||||
|
xs.append((radical(n), n))
|
||||||
|
xs = sorted(xs)
|
||||||
|
return xs[10000 - 1][1]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_124()
|
||||||
|
print("e124.py: " + str(solution))
|
||||||
|
assert(solution == 21417)
|
||||||
23
python/e125.py
Normal file
23
python/e125.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from lib_misc import is_palindrome
|
||||||
|
|
||||||
|
|
||||||
|
def euler_125():
|
||||||
|
upper = 10**8
|
||||||
|
ns = set()
|
||||||
|
for i in range(1, upper):
|
||||||
|
i2 = i * i
|
||||||
|
if i2 >= upper:
|
||||||
|
break
|
||||||
|
for j in range(i + 1, upper):
|
||||||
|
i2 += (j * j)
|
||||||
|
if i2 >= upper:
|
||||||
|
break
|
||||||
|
if is_palindrome(i2):
|
||||||
|
ns.add(i2)
|
||||||
|
return sum(ns)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_125()
|
||||||
|
print("e125.py: " + str(solution))
|
||||||
|
assert(solution == 2906969179)
|
||||||
141
python/e126.py
Normal file
141
python/e126.py
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
CUBE_THRESHOLD = 10000
|
||||||
|
|
||||||
|
def base_cubes(xlen, ylen, zlen) -> set:
|
||||||
|
r = set()
|
||||||
|
for x in range(xlen):
|
||||||
|
for y in range(ylen):
|
||||||
|
for z in range(zlen):
|
||||||
|
r.add((x, y, z))
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def neighbors(x, y, z) -> list:
|
||||||
|
dirs = [
|
||||||
|
(1, 0, 0),
|
||||||
|
(-1, 0, 0),
|
||||||
|
(0, 1, 0),
|
||||||
|
(0, -1, 0),
|
||||||
|
(0, 0, 1),
|
||||||
|
(0, 0, -1),
|
||||||
|
]
|
||||||
|
return [(x + dx, y + dy, z + dz) for dx, dy, dz in dirs]
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def count_cubes_per_layer(x, y, z) -> list:
|
||||||
|
""" First iteration. Naively add outer layers. """
|
||||||
|
r = []
|
||||||
|
clayer = base_cubes(x, y, z)
|
||||||
|
players = set(clayer)
|
||||||
|
while True:
|
||||||
|
nlayer = set()
|
||||||
|
for c in clayer:
|
||||||
|
for nb in neighbors(*c):
|
||||||
|
if nb not in players:
|
||||||
|
nlayer.add(nb)
|
||||||
|
clayer = nlayer
|
||||||
|
players |= clayer
|
||||||
|
layer_count = len(nlayer)
|
||||||
|
r.append(layer_count)
|
||||||
|
if layer_count > CUBE_THRESHOLD:
|
||||||
|
break
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def count_cubes_per_layer2(x, y, z) -> list:
|
||||||
|
""" Second iteration. Realized that the delta between the layers grows by
|
||||||
|
the same value. """
|
||||||
|
r = []
|
||||||
|
clayer = base_cubes(x, y, z)
|
||||||
|
players = set(clayer)
|
||||||
|
layer_0 = 0
|
||||||
|
layer_1 = 0
|
||||||
|
for i in range(2):
|
||||||
|
nlayer = set()
|
||||||
|
for c in clayer:
|
||||||
|
for nb in neighbors(*c):
|
||||||
|
if nb not in players:
|
||||||
|
nlayer.add(nb)
|
||||||
|
clayer = nlayer
|
||||||
|
players |= clayer
|
||||||
|
layer_count = len(nlayer)
|
||||||
|
if i == 0:
|
||||||
|
layer_0 = layer_count
|
||||||
|
elif i == 1:
|
||||||
|
layer_1 = layer_count
|
||||||
|
r.append(layer_count)
|
||||||
|
if layer_count > CUBE_THRESHOLD:
|
||||||
|
break
|
||||||
|
|
||||||
|
layer = r[-1]
|
||||||
|
layer_delta = (layer_1 - layer_0) + 8
|
||||||
|
while layer <= CUBE_THRESHOLD:
|
||||||
|
layer += layer_delta
|
||||||
|
r.append(layer)
|
||||||
|
layer_delta += 8
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def count_cubes_per_layer3(x, y, z) -> list:
|
||||||
|
""" Third iteration. Calculate first two layers directly, and then use
|
||||||
|
constant delta approach from second iteration. """
|
||||||
|
r = []
|
||||||
|
layer_0 = 2 * (x * y + x * z + y * z)
|
||||||
|
layer_1 = layer_0 + 4 * (x + y + z)
|
||||||
|
r = [layer_0, layer_1]
|
||||||
|
layer = r[-1]
|
||||||
|
layer_delta = (layer_1 - layer_0) + 8
|
||||||
|
while layer <= CUBE_THRESHOLD:
|
||||||
|
layer += layer_delta
|
||||||
|
r.append(layer)
|
||||||
|
layer_delta += 8
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_126():
|
||||||
|
# We assume that the least n for which C(n) is equal to `target`
|
||||||
|
# is under `layer_min_threshold`. We got this my trial and error.
|
||||||
|
layer_min_threshold = 20000
|
||||||
|
target = 1000
|
||||||
|
|
||||||
|
layers = defaultdict(int)
|
||||||
|
for x in range(1, layer_min_threshold):
|
||||||
|
for y in range(1, x + 1):
|
||||||
|
|
||||||
|
# If we exceed the threshold, cut the loop short.
|
||||||
|
if 2 * x * y > layer_min_threshold:
|
||||||
|
break
|
||||||
|
|
||||||
|
for z in range(1, y + 1):
|
||||||
|
layer_0 = 2 * (x * y + x * z + y * z)
|
||||||
|
layer_1 = layer_0 + 4 * (x + y + z)
|
||||||
|
|
||||||
|
layers[layer_0] += 1
|
||||||
|
layers[layer_1] += 1
|
||||||
|
|
||||||
|
layer = layer_1
|
||||||
|
layer_delta = (layer_1 - layer_0) + 8
|
||||||
|
|
||||||
|
# If we exceed the threshold, cut the loop short.
|
||||||
|
while layer < layer_min_threshold:
|
||||||
|
layer += layer_delta
|
||||||
|
layer_delta += 8
|
||||||
|
layers[layer] += 1
|
||||||
|
|
||||||
|
# Find the actual least value n for which C(n) == target.
|
||||||
|
layermin = 10**9
|
||||||
|
for n in layers.keys():
|
||||||
|
if layers[n] == target and n < layermin:
|
||||||
|
layermin = n
|
||||||
|
return layermin
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_126()
|
||||||
|
print("e126.py: " + str(solution))
|
||||||
|
assert(solution == 18522)
|
||||||
67
python/e127.py
Normal file
67
python/e127.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
from lib_prime import prime_factors
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=200000)
|
||||||
|
def unique_factors(n: int) -> set[int]:
|
||||||
|
return set(prime_factors(n))
|
||||||
|
|
||||||
|
|
||||||
|
def euler_127():
|
||||||
|
c_max = 120000
|
||||||
|
r = 0
|
||||||
|
|
||||||
|
# for a in [5]:
|
||||||
|
for a in range(1, c_max):
|
||||||
|
fsa = unique_factors(a)
|
||||||
|
# for b in [27]:
|
||||||
|
for b in range(a + 1, c_max):
|
||||||
|
if a + b > c_max:
|
||||||
|
break
|
||||||
|
c = a + b
|
||||||
|
rad = 1
|
||||||
|
|
||||||
|
do_continue = False
|
||||||
|
for fa in fsa:
|
||||||
|
rad *= fa
|
||||||
|
if b % fa == 0:
|
||||||
|
do_continue = True
|
||||||
|
break
|
||||||
|
if c % fa == 0:
|
||||||
|
do_continue = True
|
||||||
|
break
|
||||||
|
if do_continue:
|
||||||
|
continue
|
||||||
|
if rad > c:
|
||||||
|
continue
|
||||||
|
|
||||||
|
do_continue = False
|
||||||
|
fsb = unique_factors(b)
|
||||||
|
for fb in fsb:
|
||||||
|
rad *= fb
|
||||||
|
if c % fb == 0:
|
||||||
|
do_continue = True
|
||||||
|
break
|
||||||
|
if do_continue:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if rad >= c:
|
||||||
|
continue
|
||||||
|
|
||||||
|
fsc = unique_factors(c)
|
||||||
|
for fc in fsc:
|
||||||
|
rad *= fc
|
||||||
|
if rad >= c:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# print(fsa, fsb, fsc)
|
||||||
|
# print(a, b, c)
|
||||||
|
r += c
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_127()
|
||||||
|
print("e127.py: " + str(solution))
|
||||||
|
assert(solution == 18407904)
|
||||||
|
|
||||||
211
python/e128.py
Normal file
211
python/e128.py
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
from lib_prime import primes, is_prime_rabin_miller
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
def first_approach():
|
||||||
|
""" This was my original naiv approach that worked, but was way to slow
|
||||||
|
because we computed the whole hex tile grid. """
|
||||||
|
ps = set(primes(1000000))
|
||||||
|
hextiles = {(0, 0): 1}
|
||||||
|
add_ring(1, hextiles)
|
||||||
|
add_ring(2, hextiles)
|
||||||
|
|
||||||
|
# Visualization of how the coord system for the hex tile grid works.
|
||||||
|
#
|
||||||
|
# 2 1 0 1 2
|
||||||
|
# 4 8
|
||||||
|
# 3 9 19
|
||||||
|
# 2 10 2 18
|
||||||
|
# 1 3 7
|
||||||
|
# 0 11 1 17
|
||||||
|
# 1 4 6
|
||||||
|
# 2 12 5 16
|
||||||
|
# 3 13 15
|
||||||
|
# 4 14
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
pds = [1, 2, 8]
|
||||||
|
for n in range(0, 100):
|
||||||
|
ring_coord = ring_start(n)
|
||||||
|
print(" ", ring_coord, hextiles[ring_coord])
|
||||||
|
if n % 10 == 0:
|
||||||
|
print(n)
|
||||||
|
add_ring(n + 1, hextiles)
|
||||||
|
for coord in ring_coords(n):
|
||||||
|
pdv = pd(coord, hextiles, ps)
|
||||||
|
if pdv == 3:
|
||||||
|
v = hextiles[coord]
|
||||||
|
assert v == first_number_ring(n) or v == first_number_ring(n + 1) - 1
|
||||||
|
pds.append(hextiles[coord])
|
||||||
|
print(len(pds))
|
||||||
|
print(sorted(pds))
|
||||||
|
target = 10
|
||||||
|
if len(pds) >= target:
|
||||||
|
return sorted(pds)[target - 1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def ring_start(n):
|
||||||
|
return (-n * 2, 0)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def first_number_ring(n):
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
elif n == 1:
|
||||||
|
return 2
|
||||||
|
else:
|
||||||
|
return first_number_ring(n - 1) + (n - 1) * 6
|
||||||
|
|
||||||
|
|
||||||
|
def get_nbvs_ring_start(n):
|
||||||
|
# 8 1
|
||||||
|
# 9 19 2 6
|
||||||
|
# 2 0
|
||||||
|
# 3 7 3 5
|
||||||
|
# l 4
|
||||||
|
v0 = first_number_ring(n)
|
||||||
|
v1 = first_number_ring(n + 1)
|
||||||
|
v2 = v1 + 1
|
||||||
|
v3 = v0 + 1
|
||||||
|
v4 = first_number_ring(n - 1)
|
||||||
|
v5 = v1 - 1
|
||||||
|
v6 = first_number_ring(n + 2) - 1
|
||||||
|
nbvs = [v1, v2, v3, v4, v5, v6]
|
||||||
|
# print(v0, nbvs)
|
||||||
|
return nbvs
|
||||||
|
|
||||||
|
|
||||||
|
def pd_ring_start(n):
|
||||||
|
v0 = first_number_ring(n)
|
||||||
|
nbvs = get_nbvs_ring_start(n)
|
||||||
|
r = 0
|
||||||
|
for v in nbvs:
|
||||||
|
if is_prime_rabin_miller(abs(v0 - v)):
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def get_nbvs_ring_prev(n):
|
||||||
|
""" Get neighbors and values for tile before top tile. """
|
||||||
|
v0 = first_number_ring(n + 1) - 1
|
||||||
|
v1 = first_number_ring(n + 2) - 1
|
||||||
|
v2 = first_number_ring(n)
|
||||||
|
v3 = first_number_ring(n - 1)
|
||||||
|
v4 = v2 - 1
|
||||||
|
v5 = first_number_ring(n + 1) - 2
|
||||||
|
v6 = v1 - 1
|
||||||
|
nbvs = [v1, v2, v3, v4, v5, v6]
|
||||||
|
# print(v0, nbvs)
|
||||||
|
return nbvs
|
||||||
|
|
||||||
|
|
||||||
|
def pd_ring_prev(n):
|
||||||
|
v0 = first_number_ring(n + 1) - 1
|
||||||
|
nbvs = get_nbvs_ring_prev(n)
|
||||||
|
r = 0
|
||||||
|
for v in nbvs:
|
||||||
|
if is_prime_rabin_miller(abs(v0 - v)):
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def add_ring(n, numbers):
|
||||||
|
""" Adds ring n coords and values to numbers. """
|
||||||
|
if n == 0:
|
||||||
|
return
|
||||||
|
first_coord = ring_start(n)
|
||||||
|
current_number = first_number_ring(n)
|
||||||
|
numbers[first_coord] = current_number
|
||||||
|
current_coord = tuple(first_coord)
|
||||||
|
|
||||||
|
for ro, co in [(1, -1), (2, 0), (1, 1), (-1, 1), (-2, 0), (-1, -1)]:
|
||||||
|
for _ in range(n):
|
||||||
|
current_coord = (current_coord[0] + ro, current_coord[1] + co)
|
||||||
|
current_number += 1
|
||||||
|
numbers[current_coord] = current_number
|
||||||
|
|
||||||
|
# Reset first coord which is overriden.
|
||||||
|
numbers[first_coord] = first_number_ring(n)
|
||||||
|
|
||||||
|
|
||||||
|
def get_neighbor_values(coord, numbers):
|
||||||
|
neighbors = []
|
||||||
|
|
||||||
|
for ro, co in [(-2, 0), (-1, 1), (1, 1), (2, 0), (1, -1), (-1, -1)]:
|
||||||
|
nc = (coord[0] + ro, coord[1] + co)
|
||||||
|
neighbors.append(numbers[nc])
|
||||||
|
return neighbors
|
||||||
|
|
||||||
|
|
||||||
|
def ring_coords(n):
|
||||||
|
""" Returns coords for ring n. """
|
||||||
|
if n == 0:
|
||||||
|
yield (0, 0)
|
||||||
|
current_coord = ring_start(n)
|
||||||
|
for ro, co in [(1, -1), (2, 0), (1, 1), (-1, 1), (-2, 0), (-1, -1)]:
|
||||||
|
for _ in range(n):
|
||||||
|
current_coord = (current_coord[0] + ro, current_coord[1] + co)
|
||||||
|
yield current_coord
|
||||||
|
|
||||||
|
|
||||||
|
def pd(coord, numbers, primes):
|
||||||
|
prime_delta = 0
|
||||||
|
v = numbers[coord]
|
||||||
|
for nbv in get_neighbor_values(coord, numbers):
|
||||||
|
if abs(v - nbv) in primes:
|
||||||
|
prime_delta += 1
|
||||||
|
return prime_delta
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_nbvs_functions():
|
||||||
|
""" Make sure that the function to compute the neighbor values works
|
||||||
|
correctly by comparing the values to the original grid based approach. """
|
||||||
|
hextiles = {(0, 0): 1}
|
||||||
|
add_ring(1, hextiles)
|
||||||
|
add_ring(2, hextiles)
|
||||||
|
|
||||||
|
for n in range(2, 30):
|
||||||
|
add_ring(n + 1, hextiles)
|
||||||
|
nbvs1 = get_nbvs_ring_start(n)
|
||||||
|
ring_coord = ring_start(n)
|
||||||
|
nbvs2 = get_neighbor_values(ring_coord, hextiles)
|
||||||
|
assert sorted(nbvs1) == sorted(nbvs2)
|
||||||
|
|
||||||
|
nbvs1 = get_nbvs_ring_prev(n)
|
||||||
|
ring_coord = (ring_start(n)[0] + 1, ring_start(n)[1] + 1)
|
||||||
|
nbvs2 = get_neighbor_values(ring_coord, hextiles)
|
||||||
|
assert sorted(nbvs1) == sorted(nbvs2)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_128():
|
||||||
|
# Conjecture: PD3s only occur at ring starts or at ring start minus one.
|
||||||
|
# Under this assumption, we can significantly reduce the search space.
|
||||||
|
# The only challenge is to find a way to directly compute the relevant
|
||||||
|
# coords and neighbor values.
|
||||||
|
|
||||||
|
test_get_nbvs_functions()
|
||||||
|
|
||||||
|
target = 2000
|
||||||
|
pds = [1, 2]
|
||||||
|
for n in range(2, 80000):
|
||||||
|
if pd_ring_start(n) == 3:
|
||||||
|
v0 = first_number_ring(n)
|
||||||
|
pds.append(v0)
|
||||||
|
|
||||||
|
if pd_ring_prev(n) == 3:
|
||||||
|
v0 = first_number_ring(n + 1) - 1
|
||||||
|
pds.append(v0)
|
||||||
|
|
||||||
|
assert len(pds) > target
|
||||||
|
return sorted(pds)[target - 1]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_128()
|
||||||
|
print("e128.py: " + str(solution))
|
||||||
|
assert(solution == 14516824220)
|
||||||
|
|
||||||
|
|
||||||
58
python/e129.py
Normal file
58
python/e129.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
from math import gcd
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def r(n):
|
||||||
|
assert n > 0
|
||||||
|
if n == 1:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 10**(n - 1) + r(n - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def r_closed_form(n):
|
||||||
|
assert n > 0
|
||||||
|
return (10**n - 1) // 9
|
||||||
|
|
||||||
|
|
||||||
|
def r_modulo_closed_form(n, m):
|
||||||
|
assert n > 0 and m > 0
|
||||||
|
return ((pow(10, n, 9 * m) - 1) // 9) % m
|
||||||
|
|
||||||
|
|
||||||
|
def a(n):
|
||||||
|
assert gcd(n, 10) == 1
|
||||||
|
k = 1
|
||||||
|
while True:
|
||||||
|
if r_modulo_closed_form(k, n) == 0:
|
||||||
|
return k
|
||||||
|
k += 1
|
||||||
|
|
||||||
|
|
||||||
|
def euler_129():
|
||||||
|
|
||||||
|
# Comparing naiv to efficient implementations to find potential bugs.
|
||||||
|
for n in range(5, 1000):
|
||||||
|
assert r(n) == r_closed_form(n)
|
||||||
|
for m in range(2, 20):
|
||||||
|
assert (r_closed_form(n) % m) == r_modulo_closed_form(n, m)
|
||||||
|
|
||||||
|
assert a(7) == 6
|
||||||
|
assert a(41) == 5
|
||||||
|
assert a(17) == 16
|
||||||
|
|
||||||
|
target = 10**6
|
||||||
|
delta = 200
|
||||||
|
for n in range(target, target + delta):
|
||||||
|
if gcd(n, 10) == 1:
|
||||||
|
if (av := a(n)):
|
||||||
|
if av > target:
|
||||||
|
return n
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_129()
|
||||||
|
print("e129.py: " + str(solution))
|
||||||
|
assert(solution == 1000023)
|
||||||
32
python/e130.py
Normal file
32
python/e130.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from math import gcd
|
||||||
|
from lib_prime import is_prime_rabin_miller
|
||||||
|
|
||||||
|
|
||||||
|
def r_modulo_closed_form(n, m):
|
||||||
|
assert n > 0 and m > 0
|
||||||
|
return ((pow(10, n, 9 * m) - 1) // 9) % m
|
||||||
|
|
||||||
|
|
||||||
|
def a_special(n):
|
||||||
|
k = n - 1
|
||||||
|
if r_modulo_closed_form(k, n) == 0:
|
||||||
|
return k
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def euler_130():
|
||||||
|
c, r = 0, 0
|
||||||
|
for n in range(2, 10**9):
|
||||||
|
if gcd(n, 10) == 1 and not is_prime_rabin_miller(n):
|
||||||
|
if a_special(n) is not None:
|
||||||
|
r += n
|
||||||
|
c += 1
|
||||||
|
if c == 25:
|
||||||
|
break
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_130()
|
||||||
|
print("e130.py: " + str(solution))
|
||||||
|
assert(solution == 149253)
|
||||||
29
python/e131.py
Normal file
29
python/e131.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
|
||||||
|
|
||||||
|
def is_cube(n):
|
||||||
|
if n == 0:
|
||||||
|
return False
|
||||||
|
return round(n ** (1/3)) ** 3 == n
|
||||||
|
|
||||||
|
|
||||||
|
def euler_131():
|
||||||
|
r = 0
|
||||||
|
ps = primes(10**6)
|
||||||
|
minm = 1
|
||||||
|
for p in ps:
|
||||||
|
for m in range(minm, minm + 20):
|
||||||
|
n = m * m * m
|
||||||
|
x = n * n * n + n * n * p
|
||||||
|
if is_cube(x):
|
||||||
|
# print(p, n)
|
||||||
|
r += 1
|
||||||
|
minm = m
|
||||||
|
break
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_131()
|
||||||
|
print("e131.py: " + str(solution))
|
||||||
|
assert(solution == 173)
|
||||||
32
python/e132.py
Normal file
32
python/e132.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
|
||||||
|
|
||||||
|
def r_modulo_closed_form(n, m):
|
||||||
|
assert n > 0 and m > 0
|
||||||
|
return ((pow(10, n, 9 * m) - 1) // 9) % m
|
||||||
|
|
||||||
|
|
||||||
|
def is_factor(n, m):
|
||||||
|
return pow(10, n, 9 * m) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def repunit_factor_sum(n):
|
||||||
|
ps = []
|
||||||
|
for p in primes(10**6):
|
||||||
|
assert is_factor(n, p) == (r_modulo_closed_form(n, p) == 0)
|
||||||
|
if r_modulo_closed_form(n, p) == 0:
|
||||||
|
ps.append(p)
|
||||||
|
if len(ps) == 40:
|
||||||
|
break
|
||||||
|
return sum(ps)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_132():
|
||||||
|
assert repunit_factor_sum(10) == 9414
|
||||||
|
return repunit_factor_sum(10**9)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_132()
|
||||||
|
print("e132.py: " + str(solution))
|
||||||
|
assert solution == 843296
|
||||||
|
|
||||||
23
python/e133.py
Normal file
23
python/e133.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
|
||||||
|
|
||||||
|
def r_modulo_closed_form(n, m):
|
||||||
|
assert n > 0 and m > 0
|
||||||
|
return ((pow(10, n, 9 * m) - 1) // 9) % m
|
||||||
|
|
||||||
|
|
||||||
|
def euler_132():
|
||||||
|
n = 10**20
|
||||||
|
r = 0
|
||||||
|
for p in primes(100_000):
|
||||||
|
if r_modulo_closed_form(n, p) == 0:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
r += p
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_132()
|
||||||
|
print("e132.py: " + str(solution))
|
||||||
|
assert solution == 453647705
|
||||||
72
python/e134.py
Normal file
72
python/e134.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
from math import log, ceil
|
||||||
|
|
||||||
|
|
||||||
|
def s(p1, p2):
|
||||||
|
p1l = ceil(log(p1, 10))
|
||||||
|
base = 10**p1l
|
||||||
|
for lhs in range(base, 10**12, base):
|
||||||
|
r = lhs + p1
|
||||||
|
if r % p2 == 0:
|
||||||
|
return r
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def s2(p1, p2):
|
||||||
|
# Invert, always invert... but still slow, haha
|
||||||
|
p1l = ceil(log(p1, 10))
|
||||||
|
base = 10**p1l
|
||||||
|
c = p2
|
||||||
|
while True:
|
||||||
|
if c % base == p1:
|
||||||
|
return c
|
||||||
|
c += p2
|
||||||
|
|
||||||
|
|
||||||
|
def ext_gcd(a, b):
|
||||||
|
if a == 0:
|
||||||
|
return (b, 0, 1)
|
||||||
|
else:
|
||||||
|
gcd, x, y = ext_gcd(b % a, a)
|
||||||
|
return (gcd, y - (b // a) * x, x)
|
||||||
|
|
||||||
|
|
||||||
|
def modinv(a, b):
|
||||||
|
gcd, x, _ = ext_gcd(a, b)
|
||||||
|
if gcd != 1:
|
||||||
|
raise Exception('Modular inverse does not exist')
|
||||||
|
else:
|
||||||
|
return x % b
|
||||||
|
|
||||||
|
|
||||||
|
def s3(p1, p2):
|
||||||
|
# Okay with some math we are fast.
|
||||||
|
d = 10**ceil(log(p1, 10))
|
||||||
|
dinv = modinv(d, p2)
|
||||||
|
k = ((p2 - p1) * dinv) % p2
|
||||||
|
r = k * d + p1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_134():
|
||||||
|
ps = primes(10000)
|
||||||
|
for i in range(2, len(ps) - 1):
|
||||||
|
p1, p2 = ps[i], ps[i + 1]
|
||||||
|
sc = s(p1, p2)
|
||||||
|
sc2 = s2(p1, p2)
|
||||||
|
sc3 = s3(p1, p2)
|
||||||
|
assert sc == sc2 and sc2 == sc3
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
ps = primes(10**6 + 10) # p1 < 10**6 but p2 is the first p > 10**6
|
||||||
|
for i in range(2, len(ps) - 1):
|
||||||
|
p1, p2 = ps[i], ps[i + 1]
|
||||||
|
sc = s3(p1, p2)
|
||||||
|
r += sc
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_134()
|
||||||
|
print("e134.py: " + str(solution))
|
||||||
|
assert solution == 18613426663617118
|
||||||
37
python/e135.py
Normal file
37
python/e135.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
def euler_135():
|
||||||
|
n = 10**7
|
||||||
|
threshold = 10**6
|
||||||
|
lookup = {i: 0 for i in range(1, threshold)}
|
||||||
|
firstpositivestart = 1
|
||||||
|
for x in range(1, n):
|
||||||
|
firstpositive = False
|
||||||
|
for dxy in range(firstpositivestart, x // 2 + 1):
|
||||||
|
z = x - 2 * dxy
|
||||||
|
if z <= 0:
|
||||||
|
break
|
||||||
|
y = x - dxy
|
||||||
|
xyz = x*x - y*y - z*z
|
||||||
|
if xyz <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Start when xyz is already greater than 0.
|
||||||
|
if not firstpositive:
|
||||||
|
firstpositivestart = dxy
|
||||||
|
firstpositive = True
|
||||||
|
|
||||||
|
# If xyz is greater than threshold there are no more solutions.
|
||||||
|
if xyz >= threshold:
|
||||||
|
break
|
||||||
|
lookup[xyz] += 1
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for _, v in lookup.items():
|
||||||
|
if v == 10:
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_135()
|
||||||
|
print("e135.py: " + str(solution))
|
||||||
|
assert solution == 4989
|
||||||
37
python/e136.py
Normal file
37
python/e136.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
def euler_136():
|
||||||
|
n = 10**8
|
||||||
|
threshold = 50*10**6
|
||||||
|
lookup = [0 for _ in range(0, threshold)]
|
||||||
|
firstpositivestart = 1
|
||||||
|
for x in range(1, n):
|
||||||
|
firstpositive = False
|
||||||
|
for dxy in range(firstpositivestart, x // 2 + 1):
|
||||||
|
z = x - 2 * dxy
|
||||||
|
if z <= 0:
|
||||||
|
break
|
||||||
|
y = x - dxy
|
||||||
|
xyz = x*x - y*y - z*z
|
||||||
|
if xyz <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Start when xyz is already greater than 0.
|
||||||
|
if not firstpositive:
|
||||||
|
firstpositivestart = dxy
|
||||||
|
firstpositive = True
|
||||||
|
|
||||||
|
# If xyz is greater than threshold there are no more solutions.
|
||||||
|
if xyz >= threshold:
|
||||||
|
break
|
||||||
|
lookup[xyz] += 1
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for v in lookup:
|
||||||
|
if v == 1:
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_136()
|
||||||
|
print("e136.py: " + str(solution))
|
||||||
|
assert solution == 2544559
|
||||||
32
python/e138.py
Normal file
32
python/e138.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from math import gcd
|
||||||
|
|
||||||
|
|
||||||
|
def euler_138():
|
||||||
|
count = 12
|
||||||
|
r, m, n = 0, 2, 1
|
||||||
|
while True:
|
||||||
|
if count == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
if (m - n) % 2 == 1 and gcd(m, n) == 1: # Ensure m and n are coprime and not both odd
|
||||||
|
a = m * m - n * n
|
||||||
|
b = 2 * m * n
|
||||||
|
c = m * m + n * n
|
||||||
|
if a > b:
|
||||||
|
a, b = b, a
|
||||||
|
assert a * a + b * b == c * c
|
||||||
|
if a * 2 - 1 == b or a * 2 + 1 == b:
|
||||||
|
# print(f"{m=} {n=} l={c}")
|
||||||
|
r += c # c is L
|
||||||
|
count -= 1
|
||||||
|
n = m
|
||||||
|
m *= 4
|
||||||
|
m += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_138()
|
||||||
|
print("e138.py: " + str(solution))
|
||||||
|
assert solution == 1118049290473932
|
||||||
|
|
||||||
35
python/e139.py
Normal file
35
python/e139.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from math import gcd
|
||||||
|
|
||||||
|
|
||||||
|
def euler_139():
|
||||||
|
limit = 100_000_000
|
||||||
|
r, m, n = 0, 2, 1
|
||||||
|
while True:
|
||||||
|
a = m * m - 1 * 1
|
||||||
|
b = 2 * m * 1
|
||||||
|
c = m * m + 1 * 1
|
||||||
|
if a + b + c > limit:
|
||||||
|
return r
|
||||||
|
|
||||||
|
for n in range(1, m):
|
||||||
|
if (m - n) % 2 == 1 and gcd(m, n) == 1: # Ensure m and n are coprime and not both odd
|
||||||
|
a = m * m - n * n
|
||||||
|
b = 2 * m * n
|
||||||
|
c = m * m + n * n
|
||||||
|
if a > b:
|
||||||
|
a, b = b, a
|
||||||
|
|
||||||
|
ka, kb, kc = a, b, c
|
||||||
|
while ka + kb + kc < limit:
|
||||||
|
assert ka * ka + kb * kb == kc * kc
|
||||||
|
if kc % (kb - ka) == 0:
|
||||||
|
r += 1
|
||||||
|
ka, kb, kc = ka + a, kb + b, kc + c
|
||||||
|
m += 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_139()
|
||||||
|
print("e139.py: " + str(solution))
|
||||||
|
assert solution == 10057761
|
||||||
|
|
||||||
80
python/e141.py
Normal file
80
python/e141.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import concurrent.futures
|
||||||
|
from math import isqrt, gcd
|
||||||
|
|
||||||
|
|
||||||
|
def issqrt(n):
|
||||||
|
isq = isqrt(n)
|
||||||
|
return isq * isq == n
|
||||||
|
|
||||||
|
|
||||||
|
def have_same_ratio(a, b, c, d):
|
||||||
|
if b == 0 or d == 0:
|
||||||
|
raise ValueError("Denominators must be non-zero")
|
||||||
|
return a * d == b * c
|
||||||
|
|
||||||
|
|
||||||
|
def check_range(start, end):
|
||||||
|
local_sum = 0
|
||||||
|
for i in range(start, end):
|
||||||
|
if i % 10000 == 0:
|
||||||
|
print(i)
|
||||||
|
n = i * i
|
||||||
|
for d in range(1, i):
|
||||||
|
q = n // d
|
||||||
|
r = n % d
|
||||||
|
if r == 0:
|
||||||
|
continue
|
||||||
|
assert r < d and d < q
|
||||||
|
if have_same_ratio(d, r, q, d):
|
||||||
|
print(f"{n=} {i=} {r=} {d=} {q=}")
|
||||||
|
local_sum += n
|
||||||
|
break
|
||||||
|
return local_sum
|
||||||
|
|
||||||
|
|
||||||
|
def euler_141_brute_force():
|
||||||
|
s = 0
|
||||||
|
m = 1_000_000
|
||||||
|
range_size = 10_000
|
||||||
|
|
||||||
|
with concurrent.futures.ProcessPoolExecutor() as executor:
|
||||||
|
futures = []
|
||||||
|
for start in range(1, m, range_size):
|
||||||
|
end = min(start + range_size, m)
|
||||||
|
futures.append(executor.submit(check_range, start, end))
|
||||||
|
for future in concurrent.futures.as_completed(futures):
|
||||||
|
s += future.result()
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def euler_141():
|
||||||
|
r = 0
|
||||||
|
NMAX = 10**12
|
||||||
|
a = 1
|
||||||
|
while True:
|
||||||
|
if a**3 > NMAX:
|
||||||
|
break
|
||||||
|
for b in range(1, a):
|
||||||
|
if a**3 * b**2 > NMAX:
|
||||||
|
break
|
||||||
|
|
||||||
|
if gcd(a, b) != 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
c = 1
|
||||||
|
while True:
|
||||||
|
n = a**3 * b * c**2 + c * b**2
|
||||||
|
if n > NMAX:
|
||||||
|
break
|
||||||
|
if issqrt(n):
|
||||||
|
# print(n)
|
||||||
|
r += n
|
||||||
|
c += 1
|
||||||
|
a += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_141()
|
||||||
|
print("e141.py: " + str(solution))
|
||||||
|
assert solution == 878454337159
|
||||||
38
python/e142.py
Normal file
38
python/e142.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from math import isqrt
|
||||||
|
|
||||||
|
|
||||||
|
def iq(n):
|
||||||
|
isq = isqrt(n)
|
||||||
|
return isq * isq == n
|
||||||
|
|
||||||
|
|
||||||
|
def euler_142():
|
||||||
|
# x + y x - y x + z x - z y + z y - z
|
||||||
|
NMAX = 1_000_000
|
||||||
|
squares = [n * n for n in range(1, NMAX)]
|
||||||
|
for x in range(1, NMAX):
|
||||||
|
for s1 in squares:
|
||||||
|
y = x - s1 # s1 = x - y
|
||||||
|
if y <= 0:
|
||||||
|
break
|
||||||
|
if not iq(x + y): # s2 = x + y
|
||||||
|
continue
|
||||||
|
for s3 in squares:
|
||||||
|
z = y - s3 # s3 = y - z
|
||||||
|
if x - z <= 0:
|
||||||
|
continue
|
||||||
|
if z <= 0:
|
||||||
|
break
|
||||||
|
if not iq(y + z): # s4 = y + z
|
||||||
|
continue
|
||||||
|
if iq(x + z) and iq(x - z):
|
||||||
|
print(x, y, z, x + y + z)
|
||||||
|
return x + y + z
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_142()
|
||||||
|
print("e142.py: " + str(solution))
|
||||||
|
assert solution == 1006193
|
||||||
|
|
||||||
127
python/e143.py
Normal file
127
python/e143.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import math
|
||||||
|
import concurrent.futures
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
def attempt_1(a, b, c):
|
||||||
|
""" For the triangle with the sites a, b, c, calculate
|
||||||
|
the coordinates of C where we define A to be at (0, 0),
|
||||||
|
and B at (c, 0). """
|
||||||
|
assert a + b > c
|
||||||
|
assert a + c > b
|
||||||
|
assert b + c > a
|
||||||
|
S2 = [s**2 for s in range(120000)]
|
||||||
|
S4 = [s**4 for s in range(120000)]
|
||||||
|
|
||||||
|
a2 = S2[a]
|
||||||
|
b2 = S2[b]
|
||||||
|
c2 = S2[c]
|
||||||
|
|
||||||
|
a4 = S4[a]
|
||||||
|
b4 = S4[b]
|
||||||
|
c4 = S4[c]
|
||||||
|
|
||||||
|
# I've derived this myself but unfortunately I was completely on the wrong
|
||||||
|
# track.
|
||||||
|
x = -3 * (a4 + b4 + c4) + 6 * (a2*b2 + a2*c2 + b2*c2)
|
||||||
|
y = math.isqrt(x)
|
||||||
|
# y = math.sqrt(-3 * (a4 + b4 + c4) + 6 * (a2*b2 + a2*c2 + b2*c2))
|
||||||
|
if not y * y == x:
|
||||||
|
return "no int"
|
||||||
|
|
||||||
|
d = math.isqrt((c2 + b2 + a2 + y) // 2)
|
||||||
|
if d * d * 2 == c2 + b2 + a2 + y:
|
||||||
|
return d
|
||||||
|
else:
|
||||||
|
return "no int"
|
||||||
|
|
||||||
|
|
||||||
|
def is_square(n):
|
||||||
|
i = math.isqrt(n)
|
||||||
|
return i * i == n
|
||||||
|
|
||||||
|
|
||||||
|
def check_range(start, end, limit):
|
||||||
|
# When you realize that the angles in the middle are all 120 degress, you
|
||||||
|
# can derive the following formula with the law of cosines:
|
||||||
|
# c**2 = p**2 + p * r + r**2
|
||||||
|
rs = set()
|
||||||
|
for q in range(start, end):
|
||||||
|
for r in range(1, q):
|
||||||
|
if q + r > limit:
|
||||||
|
break
|
||||||
|
a2 = q**2 + q * r + r**2
|
||||||
|
if not is_square(a2):
|
||||||
|
continue
|
||||||
|
for p in range(1, r):
|
||||||
|
if q + r + p > limit:
|
||||||
|
break
|
||||||
|
b2 = p**2 + p * q + q**2
|
||||||
|
if not is_square(b2):
|
||||||
|
continue
|
||||||
|
|
||||||
|
c2 = p**2 + p * r + r**2
|
||||||
|
if is_square(c2):
|
||||||
|
d = p + q + r
|
||||||
|
# assert 3*(a**4 + b**4 + c**4 + d**4) == (a**2 + b**2 + c**2 + d**2)**2
|
||||||
|
print(math.sqrt(a2), math.sqrt(b2), math.sqrt(c2), d)
|
||||||
|
if d < limit:
|
||||||
|
rs.add(d)
|
||||||
|
return rs
|
||||||
|
|
||||||
|
|
||||||
|
def euler_143_brute_foce():
|
||||||
|
m = 120_000
|
||||||
|
range_size = 1000
|
||||||
|
s = set()
|
||||||
|
with concurrent.futures.ProcessPoolExecutor() as executor:
|
||||||
|
futures = []
|
||||||
|
for start in range(1, m, range_size):
|
||||||
|
end = min(start + range_size, m)
|
||||||
|
futures.append(executor.submit(check_range, start, end, m))
|
||||||
|
for future in concurrent.futures.as_completed(futures):
|
||||||
|
s |= future.result()
|
||||||
|
return sum(s)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_143():
|
||||||
|
pairs = defaultdict(set)
|
||||||
|
limit = 120_000
|
||||||
|
|
||||||
|
# Instead of bruteforcing, we can calculate 120 degree triangles directly.
|
||||||
|
#
|
||||||
|
# https://en.wikipedia.org/wiki/Integer_triangle#Integer_triangles_with_a_120%C2%B0_angle
|
||||||
|
#
|
||||||
|
# We then map one 120 angle adjacent site to another one.
|
||||||
|
for m in range(1, math.isqrt(limit)):
|
||||||
|
for n in range(1, m):
|
||||||
|
a = m**2 + m * n + n**2
|
||||||
|
b = 2*m*n + n**2
|
||||||
|
c = m**2 - n**2
|
||||||
|
assert a**2 == b**2 + b * c + c**2
|
||||||
|
|
||||||
|
k = 1
|
||||||
|
while k * (b + c) < limit:
|
||||||
|
pairs[k * b].add(k * c)
|
||||||
|
pairs[k * c].add(k * b)
|
||||||
|
k += 1
|
||||||
|
|
||||||
|
# Which ultimately allows us to construct all the triangles by iterating
|
||||||
|
# over the sides and looking up the respective next side.
|
||||||
|
xs = set()
|
||||||
|
for q in pairs:
|
||||||
|
for r in pairs[q]:
|
||||||
|
for p in pairs[r]:
|
||||||
|
if q in pairs[p]:
|
||||||
|
s = q + r + p
|
||||||
|
if s < limit:
|
||||||
|
xs.add(s)
|
||||||
|
|
||||||
|
return sum(xs)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_143()
|
||||||
|
print("e143.py: " + str(solution))
|
||||||
|
assert solution == 30758397
|
||||||
|
|
||||||
49
python/e146.py
Normal file
49
python/e146.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
from lib_prime import is_prime_rabin_miller
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
|
|
||||||
|
def follows_prime_pattern(n):
|
||||||
|
n2 = n * n
|
||||||
|
prev_prime = None
|
||||||
|
for i in [1, 3, 7, 9, 13, 27]:
|
||||||
|
p = n2 + i
|
||||||
|
if not is_prime_rabin_miller(p):
|
||||||
|
return False
|
||||||
|
if prev_prime is not None:
|
||||||
|
for x in range(prev_prime + 2, p, 2):
|
||||||
|
if is_prime_rabin_miller(x):
|
||||||
|
return False
|
||||||
|
prev_prime = p
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def check_range(n_min, n_max):
|
||||||
|
s = 0
|
||||||
|
for n in range(n_min - (n_min % 10), n_max, 10):
|
||||||
|
if n % 3 == 0:
|
||||||
|
continue
|
||||||
|
if follows_prime_pattern(n):
|
||||||
|
print(n)
|
||||||
|
s += n
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def euler_146():
|
||||||
|
s = 0
|
||||||
|
m = 150_000_000
|
||||||
|
range_size = 500_000
|
||||||
|
|
||||||
|
with concurrent.futures.ProcessPoolExecutor() as executor:
|
||||||
|
futures = []
|
||||||
|
for start in range(1, m, range_size):
|
||||||
|
end = min(start + range_size, m)
|
||||||
|
futures.append(executor.submit(check_range, start, end))
|
||||||
|
for future in concurrent.futures.as_completed(futures):
|
||||||
|
s += future.result()
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_146()
|
||||||
|
print("e146.py: " + str(solution))
|
||||||
|
assert solution == 676333270
|
||||||
35
python/e147.py
Normal file
35
python/e147.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from math import ceil
|
||||||
|
|
||||||
|
|
||||||
|
def combs_orth(rows, cols):
|
||||||
|
count = 0
|
||||||
|
for r in range(1, rows + 1):
|
||||||
|
for c in range(1, cols + 1):
|
||||||
|
cr = ceil(rows / r)
|
||||||
|
cc = ceil(cols / c)
|
||||||
|
count += cr * cc
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def combs_vert(rows, cols):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def combs(rows, cols):
|
||||||
|
return combs_orth(rows, cols) + combs_vert(rows, cols)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_147():
|
||||||
|
# assert combs(1, 1) == 1
|
||||||
|
# assert combs(2, 1) == 4
|
||||||
|
# assert combs(3, 1) == 8
|
||||||
|
# assert combs(2, 2) == 18
|
||||||
|
assert combs(2, 3) == 37 - 19
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_147()
|
||||||
|
print("e147.py: " + str(solution))
|
||||||
|
# assert(solution == 0)
|
||||||
|
|
||||||
20
python/e148.py
Normal file
20
python/e148.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
def count(i, s, c, depth):
|
||||||
|
if depth == 0:
|
||||||
|
return s + i, c + 1
|
||||||
|
for i in range(i, i * 8, i):
|
||||||
|
s, c = count(i, s, c, depth - 1)
|
||||||
|
if c == 10**9:
|
||||||
|
break
|
||||||
|
return s, c
|
||||||
|
|
||||||
|
|
||||||
|
def euler_148():
|
||||||
|
s, c = count(1, 0, 0, 11)
|
||||||
|
assert c == 10**9
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_148()
|
||||||
|
print("e148.py: " + str(solution))
|
||||||
|
assert solution == 2129970655314432
|
||||||
105
python/e149.py
Normal file
105
python/e149.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
def gen_numbers():
|
||||||
|
numbers = []
|
||||||
|
for k in range(1, 56):
|
||||||
|
n = (100_003 - 200_003*k + 300_007*k**3) % 1_000_000 - 500_000
|
||||||
|
numbers.append(n)
|
||||||
|
for k in range(56, 2000 * 2000 + 1):
|
||||||
|
n = (numbers[k-24-1] + numbers[k-55-1] + 1_000_000) % 1_000_000 - 500_000
|
||||||
|
numbers.append(n)
|
||||||
|
return numbers
|
||||||
|
|
||||||
|
|
||||||
|
def split(xs, n):
|
||||||
|
return [xs[i:i + n] for i in range(0, len(xs), n)]
|
||||||
|
|
||||||
|
|
||||||
|
def diags(rows):
|
||||||
|
n = len(rows)
|
||||||
|
diags = []
|
||||||
|
for col_i in range(-n + 1, n):
|
||||||
|
d = []
|
||||||
|
for row_i in range(n):
|
||||||
|
if col_i >= 0 and col_i < n:
|
||||||
|
d.append(rows[row_i][col_i])
|
||||||
|
col_i += 1
|
||||||
|
diags.append(d)
|
||||||
|
return diags
|
||||||
|
|
||||||
|
|
||||||
|
def anti_diags(rows):
|
||||||
|
n = len(rows)
|
||||||
|
diags = []
|
||||||
|
for col_i in range(-n + 1, n):
|
||||||
|
d = []
|
||||||
|
for row_i in range(n - 1, -1, -1):
|
||||||
|
if col_i >= 0 and col_i < n:
|
||||||
|
d.append(rows[row_i][col_i])
|
||||||
|
col_i += 1
|
||||||
|
diags.append(d)
|
||||||
|
return diags
|
||||||
|
|
||||||
|
|
||||||
|
def shorten(xs):
|
||||||
|
r = []
|
||||||
|
i = 0
|
||||||
|
while i < len(xs):
|
||||||
|
r.append(0)
|
||||||
|
if xs[i] < 0:
|
||||||
|
while i < len(xs) and xs[i] < 0:
|
||||||
|
r[-1] += xs[i]
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
while i < len(xs) and xs[i] >= 0:
|
||||||
|
r[-1] += xs[i]
|
||||||
|
i += 1
|
||||||
|
if r[0] <= 0:
|
||||||
|
r = r[1:]
|
||||||
|
if r and r[-1] <= 0:
|
||||||
|
r = r[:-1]
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def max_subarray(numbers):
|
||||||
|
"""Find the largest sum of any contiguous subarray.
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/Maximum_subarray_problem
|
||||||
|
|
||||||
|
Emberassing that I didn't come up with that myself...
|
||||||
|
"""
|
||||||
|
best_sum = -10**12
|
||||||
|
current_sum = 0
|
||||||
|
for x in numbers:
|
||||||
|
current_sum = max(x, current_sum + x)
|
||||||
|
best_sum = max(best_sum, current_sum)
|
||||||
|
return best_sum
|
||||||
|
|
||||||
|
|
||||||
|
def max_subarray_naiv(xs):
|
||||||
|
""" Naiv implementation in O(n^3) or something. """
|
||||||
|
r = 0
|
||||||
|
xs = shorten(xs)
|
||||||
|
for width in range(1, len(xs) + 1, 2):
|
||||||
|
for i in range(len(xs)):
|
||||||
|
r = max(r, sum(xs[i:i+width]))
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_149():
|
||||||
|
ns = gen_numbers()
|
||||||
|
assert ns[10-1] == -393027
|
||||||
|
assert ns[100-1] == 86613
|
||||||
|
|
||||||
|
rows = split(ns, 2000)
|
||||||
|
cols = list(map(list, zip(*rows)))
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for elems in [rows, cols, diags(rows), anti_diags(rows)]:
|
||||||
|
for xs in elems:
|
||||||
|
r = max(max_subarray(xs), r)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_149()
|
||||||
|
print("e149.py: " + str(solution))
|
||||||
|
assert solution == 52852124
|
||||||
61
python/e150.py
Normal file
61
python/e150.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
def generate_triangle():
|
||||||
|
t = 0
|
||||||
|
ts = [[]]
|
||||||
|
i_in_row, max_in_row = 0, 1
|
||||||
|
for _ in range(1, 500_500 + 1):
|
||||||
|
t = (615_949 * t + 797_807) % 2**20
|
||||||
|
s = t - 2**19
|
||||||
|
ts[-1].append(s)
|
||||||
|
i_in_row += 1
|
||||||
|
if i_in_row == max_in_row:
|
||||||
|
i_in_row = 0
|
||||||
|
max_in_row += 1
|
||||||
|
ts.append([])
|
||||||
|
ts.pop() # remove empty list
|
||||||
|
return ts
|
||||||
|
|
||||||
|
|
||||||
|
def array_to_prefix_sum_array(xs):
|
||||||
|
ys = []
|
||||||
|
current_sum = 0
|
||||||
|
for x in xs:
|
||||||
|
current_sum += x
|
||||||
|
ys.append(current_sum)
|
||||||
|
return ys
|
||||||
|
|
||||||
|
|
||||||
|
def range_sum(prefix_sum, i, j):
|
||||||
|
if i == 0:
|
||||||
|
return prefix_sum[j]
|
||||||
|
else:
|
||||||
|
return prefix_sum[j] - prefix_sum[i - 1]
|
||||||
|
|
||||||
|
|
||||||
|
def find_min_triangle(row_i, col_i, sum_triangle):
|
||||||
|
current_sum, min_sum = 0, float("inf")
|
||||||
|
left_i, right_i = col_i, col_i
|
||||||
|
while row_i < len(sum_triangle):
|
||||||
|
current_sum += range_sum(sum_triangle[row_i], left_i, right_i)
|
||||||
|
row_i += 1
|
||||||
|
right_i += 1
|
||||||
|
min_sum = min(current_sum, min_sum)
|
||||||
|
return min_sum
|
||||||
|
|
||||||
|
|
||||||
|
def euler_150():
|
||||||
|
triangle = generate_triangle()
|
||||||
|
# triangle = [[15], [-14, -7], [20, -13, -5], [-3, 8, 23, -26], [1, -4 , -5, -18, 5], [-16, 31, 2, 9, 28, 3]]
|
||||||
|
sum_triangle = [array_to_prefix_sum_array(xs) for xs in triangle]
|
||||||
|
|
||||||
|
min_triangle = float("inf")
|
||||||
|
for row_i in range(len(triangle)):
|
||||||
|
for col_i in range(len(triangle[row_i])):
|
||||||
|
potential_min = find_min_triangle(row_i, col_i, sum_triangle)
|
||||||
|
min_triangle = min(min_triangle, potential_min)
|
||||||
|
return min_triangle
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_150()
|
||||||
|
print("e150.py: " + str(solution))
|
||||||
|
assert solution == -271248680
|
||||||
31
python/e151.py
Normal file
31
python/e151.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from fractions import Fraction
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def expected_singles(sheets):
|
||||||
|
count = 0
|
||||||
|
if len(sheets) == 1 and sheets[0] == 5:
|
||||||
|
return 0
|
||||||
|
elif len(sheets) == 1:
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
weight = Fraction(1, len(sheets))
|
||||||
|
for sheet in sheets:
|
||||||
|
nsheets = list(sheets)
|
||||||
|
nsheets.remove(sheet)
|
||||||
|
for nsheet in range(sheet, 5):
|
||||||
|
nsheets.append(nsheet + 1)
|
||||||
|
count += weight * expected_singles(tuple(sorted(nsheets)))
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def euler_151():
|
||||||
|
return round(float(expected_singles(tuple([2, 3, 4, 5]))), 6)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_151()
|
||||||
|
print("e151.py: " + str(solution))
|
||||||
|
assert(solution == 0.464399)
|
||||||
|
|
||||||
40
python/e155.py
Normal file
40
python/e155.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from fractions import Fraction
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
C = 60
|
||||||
|
|
||||||
|
def parallel(a, b):
|
||||||
|
return Fraction(a * b, a + b)
|
||||||
|
|
||||||
|
|
||||||
|
def series(a, b):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache()
|
||||||
|
def caps(n):
|
||||||
|
if n == 1:
|
||||||
|
return set([C])
|
||||||
|
|
||||||
|
cs = set()
|
||||||
|
for size_a in range(1, (n // 2) + 1):
|
||||||
|
size_b = n - size_a
|
||||||
|
for a in caps(size_a):
|
||||||
|
for b in caps(size_b):
|
||||||
|
cs.add(a)
|
||||||
|
cs.add(parallel(a, b))
|
||||||
|
cs.add(series(a, b))
|
||||||
|
return cs
|
||||||
|
|
||||||
|
|
||||||
|
def euler_155():
|
||||||
|
assert len(caps(1)) == 1
|
||||||
|
assert len(caps(2)) == 3
|
||||||
|
assert len(caps(3)) == 7
|
||||||
|
return len(caps(18))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_155()
|
||||||
|
print("e155.py: " + str(solution))
|
||||||
|
assert solution == 3857447
|
||||||
39
python/e162.py
Normal file
39
python/e162.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def combs(xs, first=False):
|
||||||
|
if xs == (0, 0, 0, 0):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
c = 0
|
||||||
|
z, o, a, r = xs
|
||||||
|
|
||||||
|
if (not first) and z > 0:
|
||||||
|
c += combs((z - 1, o, a, r))
|
||||||
|
if o > 0:
|
||||||
|
c += combs((z, o - 1, a, r))
|
||||||
|
if a > 0:
|
||||||
|
c += combs((z, o, a - 1, r))
|
||||||
|
if r > 0:
|
||||||
|
c += 13 * combs((z, o, a, r - 1))
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def euler_162():
|
||||||
|
t = 0
|
||||||
|
for n in range(17):
|
||||||
|
for z in range(1, n + 1):
|
||||||
|
for o in range(1, n + 1):
|
||||||
|
for a in range(1, n + 1):
|
||||||
|
r = n - z - o - a
|
||||||
|
if not r >= 0:
|
||||||
|
continue
|
||||||
|
t += combs((z, o, a, r), True)
|
||||||
|
return hex(t)[2:].upper()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_162()
|
||||||
|
print("e162.py: " + str(solution))
|
||||||
|
assert(solution == "3D58725572C62302")
|
||||||
25
python/e164.py
Normal file
25
python/e164.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def count(last, left):
|
||||||
|
if left == 0:
|
||||||
|
return 1
|
||||||
|
c = 0
|
||||||
|
for d in range(10):
|
||||||
|
if sum(last) + d <= 9:
|
||||||
|
c += count((last[-1], d), left - 1)
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def euler_164():
|
||||||
|
c = 0
|
||||||
|
for d in range(1, 10):
|
||||||
|
c += count((d, ), 20-1)
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_164()
|
||||||
|
print("e164.py: " + str(solution))
|
||||||
|
assert solution == 378158756814587
|
||||||
57
python/e173.py
Normal file
57
python/e173.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
|
||||||
|
def tiles(size):
|
||||||
|
""" Returns the number of tiles for a square of the given size. """
|
||||||
|
return size * 4 - 4
|
||||||
|
|
||||||
|
|
||||||
|
def tiles_for_outer(size):
|
||||||
|
""" Returns the number of tiles for all possible laminae given the size of
|
||||||
|
the outermost ring. """
|
||||||
|
|
||||||
|
n_outer = tiles(size)
|
||||||
|
r = [n_outer]
|
||||||
|
for ni in range(size - 2, 2, -2):
|
||||||
|
n_outer += tiles(ni)
|
||||||
|
r.append(n_outer)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def count_tiles(size, n_max):
|
||||||
|
|
||||||
|
""" Count how many possible laminae with a size smaller the `n_max` are
|
||||||
|
possible for the given outermost ring `size`. """
|
||||||
|
|
||||||
|
n_outer = tiles(size)
|
||||||
|
if n_outer > n_max:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
count = 1
|
||||||
|
for ni in range(size - 2, 2, -2):
|
||||||
|
n_outer += tiles(ni)
|
||||||
|
if n_outer > n_max:
|
||||||
|
break
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def euler_173():
|
||||||
|
assert tiles(3) == 8
|
||||||
|
assert tiles(4) == 12
|
||||||
|
assert tiles(6) == 20
|
||||||
|
assert tiles(9) == 32
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
n_max = 10**6
|
||||||
|
edge_length = 3
|
||||||
|
for edge_length in range(3, n_max):
|
||||||
|
if tiles(edge_length) > n_max:
|
||||||
|
break
|
||||||
|
count += count_tiles(edge_length, n_max)
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_173()
|
||||||
|
print("e173.py: " + str(solution))
|
||||||
|
assert solution == 1572729
|
||||||
42
python/e174.py
Normal file
42
python/e174.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
def tiles(size):
|
||||||
|
""" Returns the number of tiles for a square of the given size. """
|
||||||
|
return size * 4 - 4
|
||||||
|
|
||||||
|
|
||||||
|
def tiles_for_outer(size, ts, limit):
|
||||||
|
""" Adds t to ts for given outer size as long as t is
|
||||||
|
smaller than the limit. """
|
||||||
|
t = tiles(size)
|
||||||
|
if t > limit:
|
||||||
|
return
|
||||||
|
ts[t] += 1
|
||||||
|
for ni in range(size - 2, 2, -2):
|
||||||
|
t += tiles(ni)
|
||||||
|
if t > limit:
|
||||||
|
break
|
||||||
|
ts[t] += 1
|
||||||
|
|
||||||
|
|
||||||
|
def euler_173():
|
||||||
|
ts = defaultdict(int)
|
||||||
|
limit = 1_000_000
|
||||||
|
|
||||||
|
for outer_size in range(3, limit // 4):
|
||||||
|
tiles_for_outer(outer_size, ts, limit)
|
||||||
|
|
||||||
|
c = 0
|
||||||
|
for n in range(1, 11):
|
||||||
|
for v in ts.values():
|
||||||
|
if v == n:
|
||||||
|
c += 1
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_173()
|
||||||
|
print("e173.py: " + str(solution))
|
||||||
|
assert solution == 209566
|
||||||
33
python/e179.py
Normal file
33
python/e179.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from lib_prime import get_divisors_count
|
||||||
|
|
||||||
|
|
||||||
|
def euler_179_orig():
|
||||||
|
r = 0
|
||||||
|
for n in range(2, 10**7):
|
||||||
|
if n % 10**5 == 0:
|
||||||
|
print(n)
|
||||||
|
if get_divisors_count(n) == get_divisors_count(n + 1):
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_179():
|
||||||
|
""" Much faster version. """
|
||||||
|
upper = 10**7
|
||||||
|
ndivs = [1 for _ in range(0, upper + 2)]
|
||||||
|
for d in range(2, upper // 2):
|
||||||
|
for i in range(d, upper + 2, d):
|
||||||
|
ndivs[i] += 1
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for i in range(2, upper + 1):
|
||||||
|
if ndivs[i] == ndivs[i + 1]:
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_179()
|
||||||
|
print("e179.py: " + str(solution))
|
||||||
|
assert(solution == 986262)
|
||||||
|
|
||||||
19
python/e187.py
Normal file
19
python/e187.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
|
||||||
|
|
||||||
|
def euler_187():
|
||||||
|
r = 0
|
||||||
|
upper = 10**8
|
||||||
|
ps = primes(upper // 2)
|
||||||
|
for i in range(len(ps)):
|
||||||
|
for j in range(i, len(ps)):
|
||||||
|
if ps[i] * ps[j] >= upper:
|
||||||
|
break
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_187()
|
||||||
|
print("e187.py: " + str(solution))
|
||||||
|
assert(solution == 17427258)
|
||||||
38
python/e188.py
Normal file
38
python/e188.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from lib_prime import prime_factors
|
||||||
|
|
||||||
|
|
||||||
|
def phi(n):
|
||||||
|
# Calculate phi using Euler's totient function
|
||||||
|
c = n
|
||||||
|
fs = set(prime_factors(n))
|
||||||
|
for f in fs:
|
||||||
|
# same as c *= (1 - 1/f)
|
||||||
|
c *= (f - 1)
|
||||||
|
c //= f
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def tetmod(a, k, m):
|
||||||
|
# https://stackoverflow.com/questions/30713648/how-to-compute-ab-mod-m
|
||||||
|
assert k > 0
|
||||||
|
if k == 1:
|
||||||
|
return a
|
||||||
|
if m == 1:
|
||||||
|
if a % 2 == 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
phi_m = phi(m)
|
||||||
|
return pow(a, phi_m + tetmod(a, k - 1, phi_m), m)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_188():
|
||||||
|
assert phi(100) == 40
|
||||||
|
assert tetmod(14, 2016, 100) == 36
|
||||||
|
return tetmod(1777, 1855, 10**8)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_188()
|
||||||
|
print("e188.py: " + str(solution))
|
||||||
|
assert solution == 95962097
|
||||||
38
python/e191.py
Normal file
38
python/e191.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def count(days_left, absent_count):
|
||||||
|
if absent_count > 1:
|
||||||
|
return 0
|
||||||
|
if days_left == 0:
|
||||||
|
return 1
|
||||||
|
if days_left < 0:
|
||||||
|
return 0
|
||||||
|
c = 0
|
||||||
|
c += count(days_left - 1, absent_count + 1) # "a"
|
||||||
|
c += count(days_left - 2, absent_count + 1) # "la"
|
||||||
|
c += count(days_left - 3, absent_count + 1) # "lla"
|
||||||
|
|
||||||
|
c += count(days_left - 1, absent_count) # "o"
|
||||||
|
c += count(days_left - 2, absent_count) # "lo"
|
||||||
|
c += count(days_left - 3, absent_count) # "llo"
|
||||||
|
|
||||||
|
if days_left == 2:
|
||||||
|
c += 1 # "ll"
|
||||||
|
|
||||||
|
if days_left == 1:
|
||||||
|
c += 1 # "l"
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def euler_191():
|
||||||
|
return count(30, 0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_191()
|
||||||
|
print("e191.py: " + str(solution))
|
||||||
|
assert(solution == 1918080160)
|
||||||
|
|
||||||
50
python/e195.py
Normal file
50
python/e195.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
def inradius(a, b, c):
|
||||||
|
s = (a + b + c) / 2
|
||||||
|
area = (s * (s - a) * (s - b) * (s - c))
|
||||||
|
inradius = area / s**2
|
||||||
|
return inradius
|
||||||
|
|
||||||
|
|
||||||
|
def euler_195():
|
||||||
|
count = 0
|
||||||
|
limit = 1053779
|
||||||
|
limit2 = limit * limit
|
||||||
|
for m in range(0, limit2):
|
||||||
|
for n in range(1, m // 2 + 1):
|
||||||
|
if math.gcd(m, n) == 1:
|
||||||
|
# Generator function from wiki for 60 degree eisenstein
|
||||||
|
# triangles.
|
||||||
|
a = m**2 - m*n + n**2
|
||||||
|
b = 2*m*n - n**2
|
||||||
|
c = m**2 - n**2
|
||||||
|
gcd = math.gcd(a, b, c)
|
||||||
|
a, b, c = a // gcd, b // gcd, c // gcd
|
||||||
|
|
||||||
|
# if gcd == 3 and inradius(a, b, c) > limit2:
|
||||||
|
# break
|
||||||
|
if inradius(a / 3, b / 3, c / 3) > limit2:
|
||||||
|
if n == 1:
|
||||||
|
return count
|
||||||
|
break
|
||||||
|
|
||||||
|
if a == b and b == c:
|
||||||
|
continue
|
||||||
|
|
||||||
|
k = 1
|
||||||
|
while True:
|
||||||
|
ir = inradius(a*k, b*k, c*k)
|
||||||
|
if ir > limit2:
|
||||||
|
break
|
||||||
|
count += 1
|
||||||
|
k += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_195()
|
||||||
|
print("e195.py: " + str(solution))
|
||||||
|
assert solution == 75085391
|
||||||
54
python/e203.py
Normal file
54
python/e203.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
|
||||||
|
def pascal_numbers_till(row):
|
||||||
|
def pascal_next(xs):
|
||||||
|
r = [xs[0]]
|
||||||
|
for i in range(len(xs) - 1):
|
||||||
|
r.append(xs[i] + xs[i + 1])
|
||||||
|
r.append(xs[-1])
|
||||||
|
return r
|
||||||
|
|
||||||
|
all = set([1])
|
||||||
|
xs = [1]
|
||||||
|
for _ in range(row - 1):
|
||||||
|
xs = pascal_next(xs)
|
||||||
|
all |= set(xs)
|
||||||
|
return sorted(list(set(all)))
|
||||||
|
|
||||||
|
|
||||||
|
def is_square_free(ps, n):
|
||||||
|
for p in ps:
|
||||||
|
if n % p == 0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def solve(n):
|
||||||
|
r = 0
|
||||||
|
pascals = pascal_numbers_till(n)
|
||||||
|
ps = [p * p for p in primes(int(sqrt(max(pascals))))]
|
||||||
|
for n in pascals:
|
||||||
|
if is_square_free(ps, n):
|
||||||
|
r += n
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
assert pascal_numbers_till(1) == [1]
|
||||||
|
assert pascal_numbers_till(2) == [1]
|
||||||
|
assert pascal_numbers_till(3) == [1, 2]
|
||||||
|
assert pascal_numbers_till(8) == [1, 2, 3, 4, 5, 6, 7, 10, 15, 20, 21, 35]
|
||||||
|
assert solve(8) == 105
|
||||||
|
|
||||||
|
|
||||||
|
def euler_203():
|
||||||
|
test()
|
||||||
|
return solve(51)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_203()
|
||||||
|
print("e203.py: " + str(solution))
|
||||||
|
assert solution == 34029210557338
|
||||||
38
python/e204.py
Normal file
38
python/e204.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def next_prime(n):
|
||||||
|
if n == 1:
|
||||||
|
return 2
|
||||||
|
ps = primes(105)
|
||||||
|
assert n < ps[-1]
|
||||||
|
for i, p in enumerate(ps):
|
||||||
|
if p == n and i + 1 < len(ps):
|
||||||
|
return ps[i + 1]
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def count(current_product, max_product, current_prime, max_prime):
|
||||||
|
if current_product > max_product:
|
||||||
|
return 0
|
||||||
|
r = 1
|
||||||
|
|
||||||
|
if current_prime > 1:
|
||||||
|
r += count(current_product * current_prime, max_product, current_prime, max_prime)
|
||||||
|
|
||||||
|
while (current_prime := next_prime(current_prime)) <= max_prime:
|
||||||
|
r += count(current_product * current_prime, max_product, current_prime, max_prime)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_204():
|
||||||
|
assert count(1, 10**8, 1, 5) == 1105
|
||||||
|
return count(1, 10**9, 1, 100)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_204()
|
||||||
|
print("e204.py: " + str(solution))
|
||||||
|
assert solution == 2944730
|
||||||
@@ -22,7 +22,7 @@ def euler_205():
|
|||||||
for six_value, six_count in get_item_counts(scores_six).items():
|
for six_value, six_count in get_item_counts(scores_six).items():
|
||||||
if four_value > six_value:
|
if four_value > six_value:
|
||||||
current_six_count += six_count
|
current_six_count += six_count
|
||||||
four_won_count += (four_count * current_six_count)
|
four_won_count += four_count * current_six_count
|
||||||
|
|
||||||
p = four_won_count / all_combinations
|
p = four_won_count / all_combinations
|
||||||
return f"{round(p, 7)}"
|
return f"{round(p, 7)}"
|
||||||
@@ -32,4 +32,3 @@ if __name__ == "__main__":
|
|||||||
solution = euler_205()
|
solution = euler_205()
|
||||||
print("e205.py: " + str(solution))
|
print("e205.py: " + str(solution))
|
||||||
# assert(solution == 0)
|
# assert(solution == 0)
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import math
|
|||||||
|
|
||||||
|
|
||||||
def is_square(apositiveint):
|
def is_square(apositiveint):
|
||||||
""" From: https://stackoverflow.com/a/2489519 """
|
"""From: https://stackoverflow.com/a/2489519"""
|
||||||
x = apositiveint // 2
|
x = apositiveint // 2
|
||||||
seen = set([x])
|
seen = set([x])
|
||||||
while x * x != apositiveint:
|
while x * x != apositiveint:
|
||||||
x = (x + (apositiveint // x)) // 2
|
x = (x + (apositiveint // x)) // 2
|
||||||
if x in seen: return False
|
if x in seen:
|
||||||
|
return False
|
||||||
seen.add(x)
|
seen.add(x)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ def canditates(current_value, depth):
|
|||||||
if depth <= 0:
|
if depth <= 0:
|
||||||
yield current_value
|
yield current_value
|
||||||
else:
|
else:
|
||||||
d = 10 ** depth
|
d = 10**depth
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
for new_value in canditates(current_value - i * d, depth - 2):
|
for new_value in canditates(current_value - i * d, depth - 2):
|
||||||
yield new_value
|
yield new_value
|
||||||
@@ -32,5 +33,4 @@ def euler_206():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
solution = euler_206()
|
solution = euler_206()
|
||||||
print("e206.py: " + str(solution))
|
print("e206.py: " + str(solution))
|
||||||
assert(solution == 1389019170)
|
assert solution == 1389019170
|
||||||
|
|
||||||
|
|||||||
40
python/e243.py
Normal file
40
python/e243.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from math import gcd
|
||||||
|
from fractions import Fraction
|
||||||
|
|
||||||
|
|
||||||
|
def product(xs):
|
||||||
|
r = 1
|
||||||
|
for x in xs:
|
||||||
|
r *= x
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def ratio(d):
|
||||||
|
r = 0
|
||||||
|
for i in range(1, d):
|
||||||
|
if gcd(i, d) == 1:
|
||||||
|
r += 1
|
||||||
|
return Fraction(r, (d - 1))
|
||||||
|
|
||||||
|
|
||||||
|
def euler_243():
|
||||||
|
target = Fraction(15499, 94744) # 0.1635881955585578
|
||||||
|
|
||||||
|
# The more prime factors, the lower the initial fraction gets. We figure
|
||||||
|
# out empirically that using primes up to 23 yields results close to the
|
||||||
|
# target fraction. We then iterate over the multiples to find the
|
||||||
|
# solution.
|
||||||
|
factors = [2, 3, 5, 7, 11, 13, 17, 19, 23]
|
||||||
|
|
||||||
|
for mul in range(1, 10):
|
||||||
|
d = mul * product(factors)
|
||||||
|
r = ratio(d)
|
||||||
|
if r < target:
|
||||||
|
return d
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_243()
|
||||||
|
print("e243.py: " + str(solution))
|
||||||
|
assert solution == 892371480
|
||||||
70
python/e293.py
Normal file
70
python/e293.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from lib_prime import primes, is_prime_rabin_miller
|
||||||
|
from math import isqrt
|
||||||
|
|
||||||
|
|
||||||
|
def next_larger_prime(n):
|
||||||
|
""" Returns the next prime larger or equal to n. """
|
||||||
|
if n == 1:
|
||||||
|
return 2
|
||||||
|
|
||||||
|
n += 1
|
||||||
|
if n % 2 == 0:
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
|
||||||
|
for _ in range(1000):
|
||||||
|
if is_prime_rabin_miller(n):
|
||||||
|
return n
|
||||||
|
n += 2
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def m(n):
|
||||||
|
higher_prime = next_larger_prime(n + 1)
|
||||||
|
m = higher_prime - n
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
|
def admissible(xs, threshold):
|
||||||
|
found = set()
|
||||||
|
numbers = [(xs[0], 0)]
|
||||||
|
|
||||||
|
while numbers:
|
||||||
|
value, index = numbers.pop()
|
||||||
|
if value >= threshold:
|
||||||
|
continue
|
||||||
|
if index == len(xs) - 1:
|
||||||
|
found.add(value)
|
||||||
|
numbers.append((value * xs[index], index))
|
||||||
|
if index < len(xs) - 1:
|
||||||
|
numbers.append((value * xs[index + 1], index + 1))
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def euler_293():
|
||||||
|
n = 10**9
|
||||||
|
assert next_larger_prime(1) == 2
|
||||||
|
assert next_larger_prime(7) == 11
|
||||||
|
assert m(630) == 11
|
||||||
|
|
||||||
|
m_set = set()
|
||||||
|
ps = primes(isqrt(n) + 10*8)
|
||||||
|
|
||||||
|
pow2 = 2
|
||||||
|
while pow2 < n:
|
||||||
|
mv = m(pow2)
|
||||||
|
m_set.add(mv)
|
||||||
|
pow2 *= 2
|
||||||
|
|
||||||
|
for i in range(len(ps)):
|
||||||
|
xs = ps[0:i + 1]
|
||||||
|
for x in admissible(xs, n):
|
||||||
|
m_set.add(m(x))
|
||||||
|
|
||||||
|
return sum(m_set)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_293()
|
||||||
|
print("e293.py: " + str(solution))
|
||||||
|
assert solution == 2209
|
||||||
70
python/e301.py
Normal file
70
python/e301.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def x_naiv(s):
|
||||||
|
zcount = s.count(0)
|
||||||
|
if zcount == 3:
|
||||||
|
return 0
|
||||||
|
elif zcount == 2:
|
||||||
|
return 1
|
||||||
|
elif zcount == 1:
|
||||||
|
sl = list(s)
|
||||||
|
sl.remove(0)
|
||||||
|
if sl[0] == sl[1]:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
s = list(s)
|
||||||
|
for i in range(len(s)):
|
||||||
|
for v in range(1, s[i] + 1):
|
||||||
|
ns = list(s)
|
||||||
|
ns[i] -= v
|
||||||
|
if x_naiv(tuple(sorted(ns))) == 0:
|
||||||
|
# Other player loses.
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def x_nim_sum(s):
|
||||||
|
""" I wasn't able to deduce this myself quickly and looked it up instead. """
|
||||||
|
return 0 if (s[0] ^ s[1] ^ s[2]) == 0 else 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_nim_functions():
|
||||||
|
assert(x_naiv(tuple([0, 0, 0])) == 0)
|
||||||
|
assert(x_naiv(tuple([1, 0, 0])) == 1)
|
||||||
|
assert(x_naiv(tuple([1, 1, 0])) == 0)
|
||||||
|
assert(x_naiv(tuple([1, 1, 1])) == 1)
|
||||||
|
assert(x_naiv(tuple([1, 2, 3])) == 0)
|
||||||
|
|
||||||
|
for n1 in range(0, 8):
|
||||||
|
for n2 in range(1, n1 + 1):
|
||||||
|
for n3 in range(1, n2 + 1):
|
||||||
|
s = tuple([n1, n2, n3])
|
||||||
|
assert x_naiv(s) == x_nim_sum(s)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_301():
|
||||||
|
test_nim_functions()
|
||||||
|
|
||||||
|
# log(2**30, 10) ~= 9 -> 1 billion easy brute force
|
||||||
|
# Probably a more efficient computation is possible by counting the permutations
|
||||||
|
# where all binary digits are zero.
|
||||||
|
# 0 0 0 -> 0
|
||||||
|
# 0 0 1 -> 0
|
||||||
|
# 0 1 1 -> 0
|
||||||
|
|
||||||
|
r = 0
|
||||||
|
for n in range(1, 2**30 + 1):
|
||||||
|
s = tuple([n, 2 * n, 3 * n])
|
||||||
|
xr = x_nim_sum(s)
|
||||||
|
if xr == 0:
|
||||||
|
r += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_301()
|
||||||
|
print("e301.py: " + str(solution))
|
||||||
|
# assert(solution == 0)
|
||||||
|
|
||||||
76
python/e345.py
Normal file
76
python/e345.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
from itertools import permutations
|
||||||
|
from heapq import heappush, heappop
|
||||||
|
|
||||||
|
|
||||||
|
m1 = """ 7 53 183 439 863
|
||||||
|
497 383 563 79 973
|
||||||
|
287 63 343 169 583
|
||||||
|
627 343 773 959 943
|
||||||
|
767 473 103 699 303"""
|
||||||
|
|
||||||
|
|
||||||
|
m2 = """ 7 53 183 439 863 497 383 563 79 973 287 63 343 169 583
|
||||||
|
627 343 773 959 943 767 473 103 699 303 957 703 583 639 913
|
||||||
|
447 283 463 29 23 487 463 993 119 883 327 493 423 159 743
|
||||||
|
217 623 3 399 853 407 103 983 89 463 290 516 212 462 350
|
||||||
|
960 376 682 962 300 780 486 502 912 800 250 346 172 812 350
|
||||||
|
870 456 192 162 593 473 915 45 989 873 823 965 425 329 803
|
||||||
|
973 965 905 919 133 673 665 235 509 613 673 815 165 992 326
|
||||||
|
322 148 972 962 286 255 941 541 265 323 925 281 601 95 973
|
||||||
|
445 721 11 525 473 65 511 164 138 672 18 428 154 448 848
|
||||||
|
414 456 310 312 798 104 566 520 302 248 694 976 430 392 198
|
||||||
|
184 829 373 181 631 101 969 613 840 740 778 458 284 760 390
|
||||||
|
821 461 843 513 17 901 711 993 293 157 274 94 192 156 574
|
||||||
|
34 124 4 878 450 476 712 914 838 669 875 299 823 329 699
|
||||||
|
815 559 813 459 522 788 168 586 966 232 308 833 251 631 107
|
||||||
|
813 883 451 509 615 77 281 613 459 205 380 274 302 35 805
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def brute_force(m):
|
||||||
|
idxs = [i for i in range(len(m))]
|
||||||
|
max_sum = 0
|
||||||
|
for idx in permutations(idxs):
|
||||||
|
temp_sum = 0
|
||||||
|
for i, j in enumerate(idx):
|
||||||
|
temp_sum += m[j][i]
|
||||||
|
if temp_sum > max_sum:
|
||||||
|
max_sum = temp_sum
|
||||||
|
return max_sum
|
||||||
|
|
||||||
|
|
||||||
|
def a_star(m):
|
||||||
|
# init heuristic function
|
||||||
|
h = {}
|
||||||
|
for i in range(len(m)):
|
||||||
|
h[i] = sum(map(min, m[i:]))
|
||||||
|
h[i + 1] = 0
|
||||||
|
|
||||||
|
states = []
|
||||||
|
for i, r in enumerate(m[0]):
|
||||||
|
state = (r + h[1], r, 1, [i])
|
||||||
|
heappush(states, state)
|
||||||
|
|
||||||
|
while states:
|
||||||
|
_, gscore, index, seen = heappop(states)
|
||||||
|
if index == len(m):
|
||||||
|
return -gscore
|
||||||
|
|
||||||
|
for row_index, row_score in enumerate(m[index]):
|
||||||
|
if row_index in seen:
|
||||||
|
continue
|
||||||
|
ngscore = gscore + row_score
|
||||||
|
nfscore = ngscore + h[index + 1]
|
||||||
|
nstate = (nfscore, ngscore, index + 1, seen + [row_index])
|
||||||
|
heappush(states, nstate)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_345():
|
||||||
|
m = list(zip(*map(lambda line: list(map(lambda n: -int(n), line.split())), m2.splitlines())))
|
||||||
|
return a_star(m)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_345()
|
||||||
|
print("e345.py: " + str(solution))
|
||||||
|
assert(solution == 13938)
|
||||||
39
python/e347.py
Normal file
39
python/e347.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from lib_prime import primes
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
def s(n):
|
||||||
|
ps = primes(n)
|
||||||
|
|
||||||
|
sum = 0
|
||||||
|
for p1_index in range(len(ps)):
|
||||||
|
p1 = ps[p1_index]
|
||||||
|
for p2_index in range(p1_index + 1, len(ps)):
|
||||||
|
p2 = ps[p2_index]
|
||||||
|
if p1 * p2 > n:
|
||||||
|
break
|
||||||
|
largest: Optional[Tuple[int, int, int]] = None
|
||||||
|
p1e = 1
|
||||||
|
while p1**p1e * p2 <= n:
|
||||||
|
p2e = 1
|
||||||
|
m = p1**p1e * p2**p2e
|
||||||
|
while m <= n:
|
||||||
|
if largest is None or m > largest[2]:
|
||||||
|
largest = (p1, p2, m)
|
||||||
|
p2e += 1
|
||||||
|
m = p1**p1e * p2**p2e
|
||||||
|
p1e += 1
|
||||||
|
assert largest is not None
|
||||||
|
sum += largest[2]
|
||||||
|
return sum
|
||||||
|
|
||||||
|
|
||||||
|
def euler_347():
|
||||||
|
assert s(100) == 2262
|
||||||
|
return s(10_000_000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_347()
|
||||||
|
print("e347.py: " + str(solution))
|
||||||
|
assert solution == 11109800204052
|
||||||
41
python/e357.py
Normal file
41
python/e357.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
def primes_sieve(nmax):
|
||||||
|
a = [0 for _ in range(nmax)]
|
||||||
|
for i in range(2, nmax):
|
||||||
|
if a[i] == 0:
|
||||||
|
for j in range(i + i, nmax, i):
|
||||||
|
a[j] = i
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
def is_number(n, primes):
|
||||||
|
f = n // 2
|
||||||
|
if primes[f] == 0:
|
||||||
|
for d in [2, f]:
|
||||||
|
if primes[d + n // d] != 0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
for d in range(1, n // 2 + 1):
|
||||||
|
if n % d == 0:
|
||||||
|
if primes[d + n // d] != 0:
|
||||||
|
return False
|
||||||
|
if d * d > n:
|
||||||
|
break
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def euler_357():
|
||||||
|
r = 1 # n = 1 is a number
|
||||||
|
ps = primes_sieve(100_000_000)
|
||||||
|
for p in range(3, len(ps)):
|
||||||
|
if ps[p] == 0:
|
||||||
|
n = p - 1
|
||||||
|
if is_number(n, ps):
|
||||||
|
r += n
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_357()
|
||||||
|
print("e357.py: " + str(solution))
|
||||||
|
assert solution == 1739023853137
|
||||||
63
python/e493.py
Normal file
63
python/e493.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
|
BALLS_PER_COLOR = 10
|
||||||
|
N_COLORS = 7
|
||||||
|
TO_DRAW = 20
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=10**9)
|
||||||
|
def count(urn, to_draw):
|
||||||
|
if to_draw == 0:
|
||||||
|
distinct_colors = sum([1 if c != BALLS_PER_COLOR else 0 for c in urn])
|
||||||
|
return distinct_colors
|
||||||
|
|
||||||
|
remaining_balls = sum(urn)
|
||||||
|
expected = 0
|
||||||
|
for color_i, color_remaining in enumerate(urn):
|
||||||
|
if color_remaining == 0:
|
||||||
|
continue
|
||||||
|
new_urn = list(urn)
|
||||||
|
new_urn[color_i] -= 1
|
||||||
|
expected_for_color = count(tuple(sorted(new_urn)), to_draw - 1)
|
||||||
|
probability = color_remaining / remaining_balls
|
||||||
|
expected += (probability * expected_for_color)
|
||||||
|
return expected
|
||||||
|
|
||||||
|
|
||||||
|
def binomial_coefficient(n, k):
|
||||||
|
if k < 0 or k > n:
|
||||||
|
return 0
|
||||||
|
if k == 0 or k == n:
|
||||||
|
return 1
|
||||||
|
k = min(k, n - k)
|
||||||
|
result = 1
|
||||||
|
for i in range(k):
|
||||||
|
result *= n - i
|
||||||
|
result //= i + 1
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def math():
|
||||||
|
# Find probability that a given color is chose in TO_DRAW draws.
|
||||||
|
combs_without_color = binomial_coefficient((N_COLORS - 1) * BALLS_PER_COLOR, TO_DRAW)
|
||||||
|
combs_with_color = binomial_coefficient(N_COLORS * BALLS_PER_COLOR, TO_DRAW)
|
||||||
|
p_single_color = 1 - (combs_without_color / combs_with_color)
|
||||||
|
# Then, expected colors is that probability times the number of colors.
|
||||||
|
return p_single_color * N_COLORS
|
||||||
|
|
||||||
|
|
||||||
|
def euler_493():
|
||||||
|
urn = [BALLS_PER_COLOR for _ in range(N_COLORS)]
|
||||||
|
c = count(tuple(urn), TO_DRAW)
|
||||||
|
c = round(c, 9)
|
||||||
|
m = round(math(), 9)
|
||||||
|
assert c == m
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_493()
|
||||||
|
print("e493.py: " + str(solution))
|
||||||
|
# assert(solution == 0)
|
||||||
|
|
||||||
54
python/e684.py
Normal file
54
python/e684.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
def r_modulo_closed_form(n, m):
|
||||||
|
# From e132.py
|
||||||
|
assert n > 0 and m > 0
|
||||||
|
return ((pow(10, n, 9 * m) - 1) // 9) % m
|
||||||
|
|
||||||
|
|
||||||
|
def s(n, mod):
|
||||||
|
a = n % 9
|
||||||
|
b = n // 9
|
||||||
|
r = (a + 1) * pow(10, b, mod) - 1
|
||||||
|
return r % mod
|
||||||
|
|
||||||
|
|
||||||
|
def s_big(n, mod):
|
||||||
|
# s = (n % 9 + 1) * 10^(n/9) - 1
|
||||||
|
# S = sum(k=0, n/9) (1 * 10^k + 2 * 10^k + ... + 9 * 10^k) - n
|
||||||
|
# = 45 * sum(k=0, n/9) 10^k - n
|
||||||
|
# = 45 * r(n/9) - n
|
||||||
|
# Plus some extra math to make n % 9 == 8 so that the above works.
|
||||||
|
|
||||||
|
r = -1
|
||||||
|
while n % 9 != 8:
|
||||||
|
n += 1
|
||||||
|
r -= s(n, mod)
|
||||||
|
|
||||||
|
r += (r_modulo_closed_form(n // 9 + 1, mod) * 45) % mod
|
||||||
|
r -= n
|
||||||
|
return r % mod
|
||||||
|
|
||||||
|
|
||||||
|
def s_big_naiv(n, mod):
|
||||||
|
r = 0
|
||||||
|
for i in range(1, n + 1):
|
||||||
|
r += s(i, mod)
|
||||||
|
if mod is not None:
|
||||||
|
r %= mod
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_684():
|
||||||
|
assert s_big_naiv(20, 11) == s_big(20, 11)
|
||||||
|
r = 0
|
||||||
|
mod = 1_000_000_007
|
||||||
|
a, b = 0, 1
|
||||||
|
for _ in range(2, 91):
|
||||||
|
a, b = b, a + b
|
||||||
|
r += s_big(b, mod)
|
||||||
|
return r % mod
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_684()
|
||||||
|
print("e684.py: " + str(solution))
|
||||||
|
assert(solution == 922058210)
|
||||||
29
python/e686.py
Normal file
29
python/e686.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
def p(leading_digits, count):
|
||||||
|
n_cutoff = 18
|
||||||
|
leading_digits_str = str(leading_digits)
|
||||||
|
n_digits = len(leading_digits_str)
|
||||||
|
j, current_leading, found = 1, 2, 0
|
||||||
|
|
||||||
|
while found < count:
|
||||||
|
current_leading *= 2
|
||||||
|
j += 1
|
||||||
|
current_leading_str = str(current_leading)
|
||||||
|
if current_leading_str[:n_digits] == leading_digits_str:
|
||||||
|
found += 1
|
||||||
|
current_leading = int(current_leading_str[:n_cutoff])
|
||||||
|
return j
|
||||||
|
|
||||||
|
|
||||||
|
def euler_686():
|
||||||
|
assert p(12, 1) == 7
|
||||||
|
assert p(12, 2) == 80
|
||||||
|
assert p(123, 45) == 12710
|
||||||
|
assert p(123, 100) == 28343
|
||||||
|
assert p(123, 1000) == 284168
|
||||||
|
return p(123, 678910)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_686()
|
||||||
|
print("e686.py: " + str(solution))
|
||||||
|
assert solution == 193060223
|
||||||
35
python/e751.py
Normal file
35
python/e751.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from math import floor
|
||||||
|
|
||||||
|
|
||||||
|
def next_b(b_prev):
|
||||||
|
b = floor(b_prev) * (b_prev - floor(b_prev) + 1)
|
||||||
|
return b
|
||||||
|
|
||||||
|
|
||||||
|
def euler_751():
|
||||||
|
|
||||||
|
min_found = 2
|
||||||
|
theta_str_orig = "2."
|
||||||
|
while len(theta_str_orig) < 26:
|
||||||
|
for n in range(min_found, 1000):
|
||||||
|
theta_str_new = str(theta_str_orig) + str(n)
|
||||||
|
b = float(theta_str_new)
|
||||||
|
theta_str = theta_str_new.replace("2.", "")
|
||||||
|
while theta_str != "":
|
||||||
|
b = next_b(b)
|
||||||
|
a_str = str(floor(b))
|
||||||
|
# print(a_str, theta_str)
|
||||||
|
if theta_str.startswith(a_str):
|
||||||
|
theta_str = theta_str.replace(a_str, "", 1)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if theta_str == "":
|
||||||
|
theta_str_orig = theta_str_new
|
||||||
|
break
|
||||||
|
return theta_str_orig
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_751()
|
||||||
|
print("e751.py: " + str(solution))
|
||||||
|
assert solution == "2.223561019313554106173177"
|
||||||
40
python/e853.py
Normal file
40
python/e853.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
def fib():
|
||||||
|
a, b = 1, 1
|
||||||
|
yield a
|
||||||
|
yield b
|
||||||
|
while True:
|
||||||
|
a, b = b, a + b
|
||||||
|
yield b
|
||||||
|
|
||||||
|
|
||||||
|
def pisano_period(fibs, n):
|
||||||
|
for period in range(2, 130):
|
||||||
|
if fibs[0] % n == fibs[period] % n and fibs[1] % n == fibs[period + 1] % n:
|
||||||
|
return period
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def euler_853():
|
||||||
|
r = 0
|
||||||
|
fs = fib()
|
||||||
|
fibs = [next(fs) for _ in range(400)]
|
||||||
|
upper = 10**9
|
||||||
|
pi_target = 120
|
||||||
|
for n in range(2, upper + 1):
|
||||||
|
# Check if pi_target is a period.
|
||||||
|
if fibs[0] % n == fibs[pi_target] % n and fibs[1] % n == fibs[pi_target + 1] % n:
|
||||||
|
# Make sure that no lower period than pi_target exits.
|
||||||
|
if pisano_period(fibs, n) == pi_target:
|
||||||
|
r += n
|
||||||
|
# print(n, prime_factors(n))
|
||||||
|
# I have noticed that the highest prime factor is always 61 or
|
||||||
|
# 2521, so we could probably also get the solution by
|
||||||
|
# enumerating the prime factors that yield a sum smaller than
|
||||||
|
# upper and have 61 or 2521 as their last factor.
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_853()
|
||||||
|
print("e853.py: " + str(solution))
|
||||||
|
assert solution == 44511058204
|
||||||
@@ -102,7 +102,6 @@ def prime_nth(n):
|
|||||||
is 1 indexed, i.e. n = 1 -> 2, n = 2 -> 3, etc.
|
is 1 indexed, i.e. n = 1 -> 2, n = 2 -> 3, etc.
|
||||||
|
|
||||||
:param n:
|
:param n:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if n == 1:
|
if n == 1:
|
||||||
return 2
|
return 2
|
||||||
|
|||||||
Reference in New Issue
Block a user