Solve problem 297
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
|||||||
|
from functools import cache
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
def fib(max_n: int) -> list[int]:
|
||||||
|
a, b = 1, 2
|
||||||
|
xs = [a]
|
||||||
|
while b <= max_n:
|
||||||
|
xs.append(b)
|
||||||
|
a, b = b, a + b
|
||||||
|
return xs
|
||||||
|
|
||||||
|
|
||||||
|
FIBS = fib(10**18)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def zgo(rem: int, i: int, count: int) -> Optional[int]:
|
||||||
|
if rem == 0:
|
||||||
|
return count
|
||||||
|
if rem < 0 or rem < FIBS[i]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
r1 = zgo(rem - FIBS[i], i + 2, count + 1)
|
||||||
|
if r1:
|
||||||
|
return r1
|
||||||
|
return zgo(rem, i + 1, count)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def z(n: int) -> int:
|
||||||
|
return zgo(n, 0, 0) or 0
|
||||||
|
|
||||||
|
|
||||||
|
def zsum(n: int) -> int:
|
||||||
|
return sum(z(i) for i in range(1, n))
|
||||||
|
|
||||||
|
|
||||||
|
def zxsgo(rem: int, i: int, xs: list[int]) -> Optional[list]:
|
||||||
|
if rem == 0:
|
||||||
|
return xs
|
||||||
|
if rem < 0 or rem < FIBS[i]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
r1 = zxsgo(rem - FIBS[i], i + 2, xs + [FIBS[i]])
|
||||||
|
if r1:
|
||||||
|
return r1
|
||||||
|
return zxsgo(rem, i + 1, xs)
|
||||||
|
|
||||||
|
|
||||||
|
def zxs(n: int) -> Optional[list]:
|
||||||
|
return zxsgo(n, 0, [])
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def zsumr(n: int) -> int:
|
||||||
|
if n == 1:
|
||||||
|
return 0
|
||||||
|
if n == 2:
|
||||||
|
return 1
|
||||||
|
if n in FIBS:
|
||||||
|
fib_i = FIBS.index(n)
|
||||||
|
a, b = FIBS[fib_i - 2], FIBS[fib_i - 1]
|
||||||
|
# print(f"zsumr({a})={zsumr(a)} zsumr({b})={zsumr(b)} {b - a}")
|
||||||
|
res = 0
|
||||||
|
|
||||||
|
# Zeckendorf sum up the previous fibonacci
|
||||||
|
res += zsumr(b)
|
||||||
|
|
||||||
|
# Zeckendorf sum up to the pervious previous fibonacci. This works because
|
||||||
|
# if we look at the Zeckendorf representations between two fibonaccis it is
|
||||||
|
# always a combination of the previous fibonacci plus the representations
|
||||||
|
# starting from zero. Since we cannot use the previous fibonacci because of
|
||||||
|
# the *nonconsecutive* requirement, it has to be the second previous.
|
||||||
|
res += zsumr(a)
|
||||||
|
|
||||||
|
# However, then for all the zsumr(a) terms we considered, that fibonacci
|
||||||
|
# a was not part of the count, so we have to add it:
|
||||||
|
res += n - b
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
for fib_i, fib in enumerate(FIBS):
|
||||||
|
if fib > n:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
fib_i -= 1
|
||||||
|
b = FIBS[fib_i] # fib before n
|
||||||
|
|
||||||
|
res = 0
|
||||||
|
res += zsumr(b) # Zeckendorf up to previous fib
|
||||||
|
res += zsumr(n - b) # Zeckendorf from b to n without last term
|
||||||
|
res += n - b # account for last term
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def euler_297():
|
||||||
|
assert zsumr(3) == 2
|
||||||
|
assert zsumr(5) == 5
|
||||||
|
assert zsumr(13) == 20
|
||||||
|
assert zsumr(89) == 235
|
||||||
|
assert zsumr(100) == 261
|
||||||
|
assert zsumr(10**6) == 7894453
|
||||||
|
|
||||||
|
assert z(1) == 1
|
||||||
|
assert z(5) == 1
|
||||||
|
assert z(14) == 2
|
||||||
|
assert z(100) == 3
|
||||||
|
return zsumr(10**17)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
solution = euler_297()
|
||||||
|
print(f"e297.py: {solution}")
|
||||||
|
assert solution == 2252639041804718029
|
||||||
Reference in New Issue
Block a user