一眼看去,就是个多重背包嘛~~

但是看一下数据范围,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;
}