P1450 [HAOI2008]硬币购物

题意

暴力显然是考虑n次多重背包。

考虑假如没有\(d_i\)的限制,那么这实际上就是一个普通的完全背包预处理,最后\(O(1)\)输出。

现在假设只有\(c_1\)这种硬币有限制,那么实际上我们只需要输出\(f_m-f_{m-(d_1+1)*c_1}\)就好了。因为既然\(c_1\)这种货币使用超过了限制,那么它必定使用了大于等于\(d_1+1\)次,也就是说我们先取出\(d_1+1\)\(c_1\)货币,剩下的容量随便装都是不合法的,那么不合法的方案数就是\(f_{m-(d_1+1)*c_1}\)

现在我们可能不止有一种硬币超出了限制,那么我们可以容斥一下,这样每次询问就可以\(2^4\)解决了。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=100010;
int n,m;
int c[5],d[5];
long long ans;
long long f[maxm];
void dfs(int now,int sum,int k)
{
	if(sum<0) return;
	if(now==5)
	{
		if(k&1) ans-=f[sum];
		else ans+=f[sum];
		return;
	}
	dfs(now+1,sum-(d[now]+1)*c[now],k+1);
	dfs(now+1,sum,k);
}
int main()
{
	for(int i=1;i<=4;i++) scanf("%d",&c[i]);
	scanf("%d",&n);
	f[0]=1;
	for(int i=1;i<=4;i++)
		for(int j=c[i];j<=maxm;j++) 
			f[j]+=f[j-c[i]];
	while(n--)
	{
		ans=0;
		for(int i=1;i<=4;i++) scanf("%d",&d[i]);
		scanf("%d",&m);
		dfs(1,m,0);
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-01-05 15:10  nofind  阅读(149)  评论(0编辑  收藏  举报