From cfaf3d44524a4c4ddeb6a5816fc9be9528923a7f Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sun, 27 Sep 2026 11:26:02 -0400 Subject: [PATCH] Solve problem 297 --- python/e297.py | 116 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 python/e297.py diff --git a/python/e297.py b/python/e297.py new file mode 100644 index 0000000..bc27756 --- /dev/null +++ b/python/e297.py @@ -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