Project Euler 169

Project Euler 169

题目

Exploring the number of different ways a number can be expressed as a sum of powers of 2

Define f(0)=1 and f(n) to be the number of different ways n can be expressed as a sum of integer powers of 2 using each power no more than twice.

For example, f(10)=5 since there are five different ways to express 10:

1+1+81+1+4+41+1+2+2+42+4+42+8

What is f(1025)?

解决方案

如果 n 是一个奇数,那么就可以从 n 划分出一个 1=20 出来,然后再从 n1 中继续进行。但注意这时 n1 不能够再从 20 继续划分了,因为再用 20 就相当于用了 3 20,不合题意。因此只能从 21 开始寻找,而这等价于值为 n12 的一个新问题。

如果 n 是一个偶数,那么可以选择不将 20=1 分出来,直接从 21 开始找,这等价于值为 n2 的一个新问题;也可以选择将两个 20 分出来,再从剩下的 n2 那一部分开始尝试将 21 划分出来,这等价于值为 n22 的新问题。

因此,假设 f(i)(i>0) 为题目中要求的划分数,可以列出如下状态转移方程:

f(i)={1ifi=1f(i12)else ifi1(mod2)f(i2)+f(i22)else

为避免子问题的重复计算,代码实现使用了记忆化搜索。

另外,用前几项查询 OEIS,结果为 A002487

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
N = 10 ** 25
mp = {}


def dfs(n: int):
if n <= 1:
return 1
if n in mp.keys():
return mp[n]
m = n >> 1
if n & 1:
mp[n] = dfs(m)
else:
mp[n] = dfs(m) + dfs(m - 1)
return mp[n]


ans = dfs(N)
print(ans)