硬币购物

洛谷的题

其实也接近正解了。如果没有硬币限制的话,就是简单的背包问题。
但现在加上限制,应该怎么办呢?
我们要想到容斥。
至于怎么想到的,算法标签里有。。。
先预处理出硬币没有限制(都有十万个)的所有方案数。
然后对于每种硬币,选了大于(d[i])个的方案都是不合法的。我们先预先选出(d[i]+1)个硬币,然后剩下的随便选,这些方案都是不合法的。剩下的随便选的方案又可以由预处理的数组得到。

#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const int N = 100005;
LL ans,f[N],tot,s,t,c[5],d[5];
int main()
{
	scanf("%lld%lld%lld%lld%lld",&c[1],&c[2],&c[3],&c[4],&tot);
	f[0]=1;
	for(int i=1;i<=4;i++)
	 for(int j=c[i];j<=100000;j++)
	  f[j]+=f[j-c[i]];
	t=(1<<4)-1;
	while(tot--)
	{
		scanf("%lld%lld%lld%lld%lld",&d[1],&d[2],&d[3],&d[4],&s);
		ans=f[s];
		for(int i=t;i;i=(i-1)&t)
		{
			LL res=0;
			bool flag=0;
			for(int j=1;j<=4;j++)
			{
				if(i&(1<<(j-1)))
				{
					flag^=1;
					res+=c[j]*(d[j]+1);
				}
			}
			if(s>=res)
			{
				if(flag) ans-=f[s-res];
				else ans+=f[s-res];
			}
		}
		printf("%lld
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/karryW/p/11721699.html