解析
- 刚开始以为是道多重背包题,但看到数据范围后发现此题并不简单
- 首先用完全背包预处理出硬币数量不限制时需要钱的数量 $ leq 100000 $ 的所有情况
- 发现在预处理中会有不合法的情况,也就是超过硬币数量限制的情况,需要减去
- 容斥原理,减去一枚硬币不合法的情况,加回两枚硬币不合法的情况,减去三枚硬币不合法的情况,加回四枚硬币不合法的情况,这里的处理就是通过 $ pm f[s - c_i * (d_i + 1)] $ 得到,可以通过枚举子集实现
Code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int tot,s,t,c[5],d[5];
LL ans,f[100005];
int main()
{
scanf("%d%d%d%d%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]];
t=(1<<4)-1;
while(tot--)
{
scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s);
ans=f[s];
for(int i=t;i;i=(i-1)&t)
{
LL res=0;
bool frog=0;
for(int j=1;j<=4;j++)
{
if(i&(1<<(j-1)))
{
frog^=1;
res+=c[j]*(d[j]+1);
}
}
if(s>=res)
{
if(frog) ans-=f[s-res];
else ans+=f[s-res];
}
}
printf("%lld
",ans);
}
return 0;
}