正题
Dp做得我心力交瘁。
这题我们可以先把无限个硬币的方案数搞出来。
然后再容斥一下。
关于这个容斥,就是-至少1个超过限制的+至少两个超过限制的-至少三个超过限制的+四个都超过限制的。
算的时候就直接用就可以了,因为剩下的东西的方案数已经算好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int tot,s;
long long d[5],c[5];
long long f[100010];
long long get1(int x){
if((d[x]+1)*c[x]<=s) return f[s-(d[x]+1)*c[x]];
else return 0;
}
long long get2(int x,int y){
if((d[x]+1)*c[x]+(d[y]+1)*c[y]<=s) return f[s-(d[x]+1)*c[x]-(d[y]+1)*c[y]];
else return 0;
}
long long get3(int x,int y,int z){
if((d[x]+1)*c[x]+(d[y]+1)*c[y]+(d[z]+1)*c[z]<=s) return f[s-(d[x]+1)*c[x]-(d[y]+1)*c[y]-(d[z]+1)*c[z]];
else return 0;
}
long long get4(){
if((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4]<=s) return f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*c[4]];
else return 0;
}
int main(){
scanf("%lld %lld %lld %lld %d",&c[1],&c[2],&c[3],&c[4],&tot);
f[0]=1;
for(int i=1;i<=4;i++)
for(int j=c[i];j<=100000;j++)
f[j]+=f[j-c[i]];
long long ans=0;
while(tot--){
scanf("%lld %lld %lld %lld %d",&d[1],&d[2],&d[3],&d[4],&s);
ans=f[s]+get2(1,2)+get2(1,3)+get2(1,4)+get2(2,3)+get2(2,4)+get2(3,4)+get4();
ans-=get1(1)+get1(2)+get1(3)+get1(4)+get3(1,2,3)+get3(1,2,4)+get3(2,3,4)+get3(1,3,4);
printf("%lld\n",ans);
}
}