luogu P1450 [HAOI2008]硬币购物

应该算是我做的正儿八经的容斥的第一道题吧。

直接做时间复杂度是\(O(4nS)\)的,显然不能接受。注意到这题只有\(4\)个物品,考虑容斥。

容斥模型

  • 元素:每一种方案
  • 全集:所有组合总和为\(n\)的方案
  • 属性:对每个物品购买的数量限制

这道题显然是对每个属性求交集,于是转化成了全集-补集的并集模型,由于只有\(4\)个物品,所以可以直接预处理+暴力枚举,时间复杂度\(O(4max(S),2^4n)\)

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long LL;
const int N=100000;
int c[5],n,d[5],s;
LL f[N+9];

void init()
{
	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<=N;j++)
			f[j]+=f[j-c[i]];
}

void work()
{
	while(n--)
	{
		for (int i=1;i<=4;i++)
			scanf("%d",&d[i]);
		scanf("%d",&s);
		LL ans=0;
		for (int i=1;i<16;i++)
		{
			int cnt=0;LL m=s;
			for (int j=1;j<=4;j++)
				if(i&(1<<j-1))
					cnt++,m-=1ll*(d[j]+1)*c[j];
			if(m>=0) ans+=(cnt&1)?f[m]:-f[m];
		}
		printf("%lld\n",f[s]-ans);
	}
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-06-06 05:56  With_penguin  阅读(93)  评论(0编辑  收藏  举报