洛谷的题
其实也接近正解了。如果没有硬币限制的话,就是简单的背包问题。
但现在加上限制,应该怎么办呢?
我们要想到容斥。
至于怎么想到的,算法标签里有。。。
先预处理出硬币没有限制(都有十万个)的所有方案数。
然后对于每种硬币,选了大于(d[i])个的方案都是不合法的。我们先预先选出(d[i]+1)个硬币,然后剩下的随便选,这些方案都是不合法的。剩下的随便选的方案又可以由预处理的数组得到。
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const int N = 100005;
LL ans,f[N],tot,s,t,c[5],d[5];
int main()
{
scanf("%lld%lld%lld%lld%lld",&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("%lld%lld%lld%lld%lld",&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 flag=0;
for(int j=1;j<=4;j++)
{
if(i&(1<<(j-1)))
{
flag^=1;
res+=c[j]*(d[j]+1);
}
}
if(s>=res)
{
if(flag) ans-=f[s-res];
else ans+=f[s-res];
}
}
printf("%lld
",ans);
}
return 0;
}