[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;
}
posted @ 2021-11-17 21:10  sky_light  阅读(44)  评论(0)    收藏  举报