刚看到题,直接想到多重背包的做法,于是写了一个裸多重背包(没有进行什么优化),很显然就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; }