一眼看去,就是个多重背包嘛~~
但是看一下数据范围,emm,好的,换思路。
首先考虑,如果没有次数限制的话,那么直接完全背包预处理,然后
询问就好了。
然后考虑容斥,从中减去不合法的方案。首先肯定会有一种硬币超额使用,对于第种硬币等于说强制选了
个,剩下的依然随便选,那么对于第
种硬币不合法的方案数等于
,于是从
里减去
就可以了。
另外,第一、二种,第一、三种,第一、四种,第二、三种,第二、四种,第三、四种都非法的方案在上一步中都被减了两次,所以额外都加一次回来。
#include<bits/stdc++.h>
#define int long long
const int N=1e5+5,INF=0x3f3f3f3f;
using namespace std;
int n,k,ans,T;
int c[5],d[5],f[N]={1};
inline int read()
{
register int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
void chu()
{
for(int i=0;i<4;i++) c[i]=read();
T=read();
for(int i=0;i<4;i++)
for(int j=c[i];j<N;j++)
f[j]+=f[j-c[i]];
}
void solve()
{
while(T--)
{
for(int i=0;i<4;i++)
d[i]=read();
int s=read();
ans=f[s];
for(int i=1;i<=15;++i)
{
int now=s;
for(int tmp=i,j=k=0;tmp;tmp>>=1,j++)
if(tmp&1) k^=1,now-=(d[j]+1)*c[j];
if(now>=0)
{
if(k)
ans-=f[now];
else
ans+=f[now];
}
}
printf("%lld\n",ans);
}
}
signed main()
{
chu();
solve();
return 0;
}

京公网安备 11010502036488号