#容斥,完全背包#洛谷 1450 [HAOI2008]硬币购物

题目


分析

直接多重背包应该会T掉,考虑硬币的种类比较少。

如果没有硬币数量的限制直接完全背包就可以了,

不然如果限制了硬币的数量那么第 (d+1) 次取这个硬币就不合法,

所以要减去 (dp[s-c*(d+1)]),考虑不重不漏,那么容斥一下就可以了


代码

#include <cstdio>
#include <cctype>
using namespace std;
const int N=100011;
typedef long long lll;
lll dp[N],w[4],b[4],m,ans;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
int main(){
	for (int i=0;i<4;++i) w[i]=iut();
	dp[0]=1;
	for (int i=0;i<4;++i)
	for (int j=w[i];j<=N-11;++j)
	    dp[j]+=dp[j-w[i]];
	for (int T=iut();T;--T){
		for (int i=0;i<4;++i) b[i]=iut();
		m=iut(),ans=0;
		for (int i=0;i<16;++i){
			int now=m,F=1;
			for (int j=0;j<4;++j)
			    if ((i>>j)&1) now-=w[j]*(b[j]+1),F=-F;
			if (now>=0) ans+=F*dp[now];
		}
		print(ans),putchar(10);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15512144.html