[HAOI2008]硬币购物 题解
这题目我觉得很强的啊……
书归正传,这道题有一个显然的多重背包做法,但是很遗憾,这题过不去,时间复杂度是
那我们不妨先考虑一个简单的东西,就是没有硬币数量的限制,那么完全背包就能秒了这个题
那有了限制之后呢?
那么发现硬币的数量只有4种,是个很好的性质
考虑容斥解决,对于第 \(j\) 个硬币,其实他的答案就是抛掉多余硬币个数的,也就是题中的 \(d_j\)
实际上,我们应该抛掉 \(d_j +1\) 个的,因为可以不选,那么就相当于减去 \(f[s-(d_j +1) \times c_j]\) ,答案就是 \(f[s]-f[s-(d_j +1) \times c_j]\)
如果算四个这玩意,就会算少,包括同时超过两个限制条件的等等,因此,就可以容斥了,具体的大概就是奇数减,偶数加
代码如下
#include<bits/stdc++.h>
const int N=100010;
using namespace std;
int T,c[10],d[10],s;
long long ans=0,f[N]={1,0};
void bag(){for(int i=1;i<=4;i++) for(int j=c[i];j<=N-1;j++) f[j]+=f[j-c[i]];}
void dfs(int x,int k,int sum){
if(sum<0) return ;
if(x==5){
if(k&1) ans-=f[sum];
else ans+=f[sum];
return ;
}
dfs(x+1,k+1,sum-c[x]*(d[x]+1)),dfs(x+1,k,sum);
}
int main(){
scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&T);
bag();
while(T-->0){
scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s);
ans=0;
dfs(1,0,s);
printf("%lld\n",ans);
}
return 0;
}