MOD = 10**7 SPACE = 10**7 CACHE = [None for _ in range(SPACE * 2)] CACHE_TILL = [None for _ in range(SPACE)] CACHE_TILL_IS_TWO_EVEN = [None for _ in range(SPACE)] CACHE_TILL_IS_TWO_ODD = [None for _ in range(SPACE)] CACHE_T_FROM_ACC = [None for _ in range(SPACE * 2)] def t_from_acc(rem: int, is_two: bool) -> int: offset = rem + SPACE * is_two if (value := CACHE_T_FROM_ACC[offset]) is not None: return value if rem < 0: return 0 s = t_from(rem, is_two) + t_from_acc(rem - 2, is_two) s %= MOD CACHE_T_FROM_ACC[offset] = s return s def t_from(rem: int, is_two: bool) -> int: offset = rem + SPACE * is_two if (value := CACHE[offset]) is not None: return value s = 0 if rem < 0: s = 0 elif rem == 1: s = 0 elif rem == 0 and is_two: s = 1 else: s += t_from(rem - 2, is_two) # d = 1 s %= MOD s += t_from(rem - 4, True) # d = 2 s %= MOD s += t_from_acc(rem - 6, is_two) s %= MOD # Naive (too slow): # for d in range(1, rem // 2 + 1): # s += t_from(rem - 2 * d, is_two or d == 2) # s %= MOD CACHE[offset] = s % MOD return s % MOD def t_old(n: int) -> int: # print(f"t({n}) = ", end="") s = 0 for i in range(0, n + 1): rem = n - i s += t_from(rem, i == 2) return s % MOD def t(n: int) -> int: s = CACHE_TILL[n - 4] assert s is not None s += t_from(n - 3, False) CACHE_TILL[n - 3] = s % MOD s += t_from(n - 2, True) s %= MOD s += t_from(n - 1, False) s %= MOD s += t_from(n, False) s %= MOD return s def euler_710(): for i in range(4): CACHE_TILL[i] = 0 for n in range(4, 50): t(n) assert t(5) == 1 assert t(6) == 4 assert t(20) == 824 assert t(42) == 1999923 for n in range(10, SPACE): tn = t(n) if tn % 10**6 == 0: # print(f"t({n}) = {tn} <<<") return n # if tn % 10000 == 0: # print(f"t({n}) = {tn}") assert False, "Solution not found" if __name__ == "__main__": solution = euler_710() print(f"e710.py: {solution}") assert solution == 1275000