链接:点击打开链接
题意:有n个程序员,要写m行代码,第i个人写一行代码必定会出现ai个bug,每个人按顺序选择写几行代码,可以不写,问恰好写m行代码并且出现的bug数目不大于b的种数
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
long long a[505],dp[2][505][505];
int main(){
long long n,m,b,i,j,k,ans,mod;
while(scanf("%I64d%I64d%I64d%I64d",&n,&m,&b,&mod)!=EOF){
for(i=1;i<=n;i++) //dp[i][j][k]表示前i个人写了j行代码有k个错误
scanf("%I64d",&a[i]); //dp[i][j][k]=dp[i][j][k]+(dp[i-1][0][k-j*a[i]]+...+dp[i-1][j][k])
memset(dp,0,sizeof(dp)); //这样转移的话复杂度是O(n^4),所以需要降低复杂度
dp[0][0][0]=1; //然而仔细观察则会发现
for(i=1;i<=n;i++){ //dp[i][j-1][k-a[i]]=dp[i][j-1][k-a[i]]+(dp[i-1][0][k-j*a[i]+...+dp[i-1][j-1][k-a[i]])
memset(dp[i%2],0,sizeof(dp[i%2])); //两个试子相减
dp[i%2][0][0]=1; //dp[i][j][k]=dp[i][j][k]+dp[i][j-1][k-a[i]]+dp[i-1][j][k]
for(j=1;j<=m;j++){ //时间复杂度也就变成O(n^3),空间上用滚动数组解决
for(k=0;k<=b;k++){
if(k>=a[i])
dp[i%2][j][k]=(dp[i%2][j][k]+dp[i%2][j-1][k-a[i]]+dp[(i-1)%2][j][k])%mod;
else
dp[i%2][j][k]=(dp[i%2][j][k]+dp[(i-1)%2][j][k])%mod;
}
}
}
ans=0;
for(k=0;k<=b;k++)
ans=(ans+dp[n%2][m][k])%mod;
printf("%I64d\n",ans);
}
return 0;
}