from typing import List, Optional from math import sqrt from functools import lru_cache def to_int(digits: List[int]) -> int: return int("".join(map(str, digits))) def int_len(n: int) -> int: return len(str(n)) @lru_cache def digits_make_sum(digits, remainder: int) -> Optional[List]: if len(digits) == 0: if remainder == 0: return [] return None remainder_digits_count = int_len(remainder) if remainder_digits_count > len(digits): return None if to_int(digits) < remainder: return None for group_size in range(1, remainder_digits_count + 1): digits_list = list(digits) rest_value = remainder - to_int(digits_list[:group_size]) rest_digits = tuple(digits_list[group_size:]) r = digits_make_sum(rest_digits, rest_value) if type(r) is list: return [digits_list[:group_size]] + r return None def digits_sum_to(digits, number: int): r = digits_make_sum(digits, number) if type(r) is list: # print(digits, r, number) return True return False def t(limit: int) -> int: r = 0 for base in range(4, int(sqrt(limit)) + 1): n = base * base n_digits = tuple(map(int, list(str(n)))) if digits_sum_to(n_digits, base): r += n return r def euler_719(): assert(t(10**4) == 41333) assert(digits_sum_to((1, 0, 0), 10) == True) assert(digits_sum_to((1, 8), 9) == True) assert(digits_sum_to((2, 5), 5) == False) assert(digits_sum_to((8, 2, 8, 1), 91) == True) assert(t(10**6) == 10804656) return t(10**12) if __name__ == "__main__": solution = euler_719() print("e719.py: " + str(solution)) assert(solution == 128088830547982)