📌  相关文章
📜  将 N 表示为 K 个偶数或 K 个奇数的总和,允许重复(1)

📅  最后修改于: 2023-12-03 14:53:44.352000             🧑  作者: Mango

将 N 表示为 K 个偶数或 K 个奇数的总和,允许重复

问题

给定正整数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]
参考资料

洛谷 P2479