从这些物品中取出m个, 有多少种取法? 求出数模M的余数.
例如: 有n=3种物品, 每种a={1,2,3}个, 取出m=3个, 取法result=6 (0+0+3, 0+1+2, 0+2+1, 1+0+2, 1+1+1, 1+2+0).
使用动态规划(DP).
前i+1种物品取出j个 = 前i+1种物品取出j-1个 + 前i种物品取出j个 - 前i种物品中取出j-1-a个.
因为取出j-1-a个, 最后需要j-1个, 则a需要全部取出, 前两个相重复, 则必然全部取出.
递推公式: dp[i+1][j] = dp[i+1][j-1] + dp[i][j] - dp[i][j-1-a]
时间复杂度O(nm).
主要是在进行递推之钱还要记得,要先给dp赋一个初值1,要赋初值的也只是每一行的第一个数,也就是dp[i][0]=1;
还有在递推时候,还要注意的一个问题就是dp[i][j-1-a]这里的时候,要进行判断一下,如果j-1-a的值小于0那个就把这个dp去掉,因为我们的数组
在这里不支持负数。这里是一些个人的代码:
仅供参考:
#include
#include
#include
using namespace std;
const int maxn=1010;
int n,m,mod;
int a[maxn];
int dp[maxn][maxn];
int main()
{
while(~scanf("%d%d%d",&n,&m,&mod))
{
for(int i=0; i
for(int i=0; i<=n; i++)
dp[i][0]=1;
for(int i=0; i
{
if(j-1-a[i]>=0)
dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]]+mod)%mod;//记得这里要在里面加上mod,不然会造成错误,因为当dp[i][j-1-a[i]]
//很大时会变成负数的情况发生
else
dp[i+1][j]=(dp[i+1][j-1]+dp[i][j])%mod;
}
printf("%d\n",dp[n][m]);
}
}