Luogu1450 HAOI2008硬币购物

(yysy) ,这个题真的是个不错的题目

Description

link

给定 (4) 种面值的硬币,然后有 (n) 次询问

每次给四个参数和一个面值,求每种硬币不使用超过参数个时凑成给定面值有多少方案

Solution

首先我们发现每次算方案显然是会飞的

然后我们可以先上来做一次完全背包,在每次询问的时候容斥

(就是(FlashHu)大佬的“询问重复利用信息”)

我们发现每次多出来的不合法方案在每种硬币使用超量的时候

所以我们就用状压 (+) 统计答案即可

说不清,具体看代码吧……

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	int c[5],d[5],s,T,f[100010];
	signed main()
	{
		for(int i=1;i<=4;++i) c[i]=read(); T=read(); f[0]=1;
		for(int i=1;i<=4;++i) 
		{
			for(int j=c[i];j<=1e5;++j) f[j]+=f[j-c[i]];
		}
		while(T--)
		{
			for(int i=1;i<=4;++i) d[i]=read(); s=read();
			int ans=f[s];
			for(int i=1;i<=15;++i)
			{
				int del=0,t=s;
				for(int j=1;j<=4;++j)
				{
					if(i&(1<<(j-1))) del++,t-=c[j]*(d[j]+1);
				} 
				if(t<0) continue;
				if(del&1) ans-=f[t];
				else ans+=f[t];
			}cout<<ans<<endl;
		}
		return 0;
	}
}
signed main(){return yspm::main();}

Review

我们在思考题目的时候可以预处理已知信息来对付重复询问

另外:需要学习枚举子集的方法

原文地址:https://www.cnblogs.com/yspm/p/12740858.html