题目链接:https://www.luogu.org/problemnew/show/P1450
题目描述:
题解:
如果去掉限制的话,这就是一个完全背包。
我们可以考虑先去掉限制,把这个完全背包做出来。
这个时候我们先考虑一种硬币超出了限制,其他硬币任意的情况。怎么处理成这种情况呢?我们假设当前超过的硬币是i,我们强制用di+1枚硬币,那么剩下的就是一个
完全背包了,这个完全背包的值就是我们现在算的第i种硬币超了,其他任意的方案数。
然后我们考虑容斥,第一种第二种都超额、第一种第三种都超额、第一种第四种都超额、第二种第三种都超额、第二种第四种都超额、第三种第四种都超额的方案在上一步中都被减了两次,所以额外都加一次回来,容斥下去就行了
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<algorithm> #define ll long long using namespace std; int tot; int c[5],d[5]; ll f[100050]; int main() { for (int i=1;i<=4;i++) scanf("%d",c+i); scanf("%d",&tot); f[0]=1; for (int i=1;i<=4;i++) for (int j=c[i];j<=100050;j++) f[j]+=f[j-c[i]]; while (tot--) { for (int i=1;i<=4;i++) scanf("%d",d+i); int s; scanf("%d",&s); ll res=0; for (int i=0;i<15;i++) { ll t=s; int cnt=0; for (int j=1;j<=4;j++) if ((i>>(j-1))&1) {t-=c[j]*(d[j]+1);cnt^=1;} if (t<0) continue; if (!cnt) res+=f[t];else res-=f[t]; } printf("%lld ",res); } return 0; }