有
n
n
n 个程序员总共需要写
m
m
m 行代码,每个程序员写一行代码都将产生
a
i
a_i
ai 个
b
u
g
bug
bug (推荐退役?) ,要求写完
m
m
m 行代码后的总
b
u
g
bug
bug 数不超过
b
b
b 。问有多少种可行的方案。
完全背包问题,因为可以由一个程序员把所有代码全部写完。由于数据范围为 500 500 500,可以发现开三维 d p dp dp 必定会炸,因此需考虑降维优化。
当采用三维时,有 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示前 i i i 个人写了 j j j 行代码并产生 k k k 个 b u g bug bug 的方案数。对于第 i i i 个人如果不写,则该状态由 f [ i − 1 ] [ j ] [ k ] f[i-1][j][k] f[i−1][j][k] 转化而来,若第 i i i 个人写,则由 f [ i − 1 ] [ j − 1 ] [ k − a [ i ] ] f[i-1][j-1][k-a[i]] f[i−1][j−1][k−a[i]] 转化而来,因此可考虑将第一维优化掉,仅考虑当第 i i i 个人写的情况。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N=550;
int f[N][N],a[N];
//f[i][j][k]=f[i-1][j-1][k-a[i]],f[i-1][j][k]
signed main(){
int n,m,b,mod;
cin>>n>>m>>b>>mod;
for(int i=1;i<=n;i++)
cin>>a[i];
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=a[i];k<=b;k++){
f[j][k]=(f[j][k]+f[j-1][k-a[i]])%mod;
}
}
}
int ans=0;
for(int i=0;i<=b;i++){
ans=(ans+f[m][i])%mod;
}
cout<<ans%mod<<endl;
return 0;
}