Luogu P1450 [HAOI2008]硬币购物


Luogu P1450 [HAOI2008]硬币购物

解析

  • 刚开始以为是道多重背包题,但看到数据范围后发现此题并不简单
  • 首先用完全背包预处理出硬币数量不限制时需要钱的数量 $ \leq 100000 $ 的所有情况
  • 发现在预处理中会有不合法的情况,也就是超过硬币数量限制的情况,需要减去
  • 容斥原理,减去一枚硬币不合法的情况,加回两枚硬币不合法的情况,减去三枚硬币不合法的情况,加回四枚硬币不合法的情况,这里的处理就是通过 $ \pm f[s - c_i * (d_i + 1)] $ 得到,可以通过枚举子集实现

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int tot,s,t,c[5],d[5];
LL ans,f[100005];
int main()
{
	scanf("%d%d%d%d%d",&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("%d%d%d%d%d",&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 frog=0;
			for(int j=1;j<=4;j++)
			{
				if(i&(1<<(j-1)))
				{
					frog^=1;
					res+=c[j]*(d[j]+1);
				}
			}
			if(s>=res)
			{
				if(frog) ans-=f[s-res];
				else ans+=f[s-res];
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-09-26 11:13  Hawking_llfz  阅读(95)  评论(0编辑  收藏  举报