📅  最后修改于: 2023-12-03 14:53:44.352000             🧑  作者: Mango
给定正整数N和正整数K,求用K个偶数或K个奇数的和表示N的方案数,允许重复。
我们可以先想象一下N和K有多大,以及最小的情况下是怎么表示的。
当N=1时,我们只能使用一个奇数来表示,也就是说K=1。
当N=2时,我们只能使用一个偶数来表示,也就是说K=1。
当N=3时,我们只能使用一个奇数来表示,也就是说K=1。
当N=4时,我们只能使用一个偶数来表示,也就是说K=1。
...
可以发现,当N是偶数时,我们只能使用偶数来表示;当N是奇数时,我们只能使用奇数来表示。
假设我们现在要表示N=5,K=3。
我们可以把问题简化为只需要用一个奇数和两个偶数来表示5的方案数,因为我们已经知道偶数只能用来表示偶数,奇数只能用来表示奇数了。
那么我们先使用一个1来表示5,然后再尝试使用两个2来表示5,表示不了,就只能使用一个1和一个4,表示得了,那么方案数为1。
再尝试使用一个2来表示5,无法表示,只能使用两个1和一个3,表示得了,那么方案数为1。
综上,方案数为2。
我们可以定义dp[i][j],表示用j个偶数或j个奇数来表示i的方案数。
那么我们可以根据前面的思考,得到转移方程:
当i是偶数时:
dp[i][j] = dp[i-2][j-1] + dp[i-4][j-1] + ... + dp[0][j-1]
当i是奇数时:
dp[i][j] = dp[i-2][j-1] + dp[i-4][j-1] + ... + dp[1][j-1]
其中,i-2、i-4等是为了保证j个数中至少有一个能表示i的,也就是保证一定有一个数是奇偶性与i相反的数。
def dp(N, K):
dp = [[0] * (K+1) for _ in range(N+1)]
for i in range(1, N+1):
dp[i][1] = 1
for i in range(2, N+1, 2):
for j in range(2, K+1):
for k in range(0, i, 2):
dp[i][j] += dp[k][j-1]
for i in range(3, N+1, 2):
for j in range(2, K+1):
for k in range(1, i, 2):
dp[i][j] += dp[k][j-1]
return dp[N][K]