刚看到题,直接想到多重背包的做法,于是写了一个裸多重背包(没有进行什么优化),很显然就t了
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=45065555&returnHomeType=1&uid=427618442
------------------------------------------------下面是正解

做法:dp+容斥原理

思路:

1.先假设硬币的数量有无限,可以利用完全背包思路来预处理
2.介绍容斥原理:
简单来说就是奇加偶减
由于我是总数去减,于是就变成了奇减偶加
3.二进制优化:

~表示选(1)或不选(0)

代码:

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp(aa,bb) make_pair(aa,bb)
#define _for(i,b) for(int i=(0);i<(b);i++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,b,a) for(int i=(b);i>=(a);i--)
#define mst(abc,bca) memset(abc,bca,sizeof abc)
#define X first
#define Y second
#define lowbit(a) (a&(-a))
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long double ld;
const int N=100010;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-6;
const double PI=acos(-1.0);

int c[5],d[5],s;
ll dp[N];

void init(){
    dp[0]=1;
    cin>>c[1]>>c[2]>>c[3]>>c[4];
    rep(i,1,4){
        for(int j=c[i];j<N;j++){
            dp[j]+=dp[j-c[i]];
        }
    }
}

void solve(){
    cin>>d[1]>>d[2]>>d[3]>>d[4]>>s;
    ll ans=dp[s];
    for(int i=1;i<=(1<<4)-1;i++){
        ll t=0;
        int cnt=0;//二进制中有几个1(奇数为1,偶数为0) 
        for(int j=1;j<=4;j++){
            if((1<<(j-1))&i) t+=c[j]*(d[j]+1),cnt^=1;
        }
        if(s>=t) ans=cnt?ans-dp[s-t]:ans+dp[s-t]; 
    }
    cout<<ans<<"\n";
}


int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
#ifdef DEBUG
    freopen("F:/laji/1.in", "r", stdin);
//    freopen("F:/laji/2.out", "w", stdout);
#endif
    init();
    int t;cin>>t;while(t--)
    solve();
    return 0;
}