首页 > 其他 > 详细

Luogu P1450 [HAOI2008]硬币购物

时间:2020-05-28 23:58:27      阅读:87      评论:0      收藏:0      [点我收藏+]

gate

背包dp+容斥,然而没想出来。
首先预处理出没有限制的方案数。
价值为\(c_i\)的硬币有\(d_i\)个,那么不合法的方案数即为\(f[c_i*(d_i+1)]\),因为若\(c_i\)超出限制,后面的再怎么选都是不合法的了。
但这样显然会有重复计算。所以,根据容斥原理,减去1种超限的,加上2种超限的,减去3种超限的,加上4种超限的。

for(int i = 1; i <= 15; i++) {
	k = 1;
	now = 0;
	for(int j = 1; j <= 4; j++)
		if((i >> (j-1)) & 1) {
			now += c[j]*(d[j]+1);
			k *= -1;
		}
	if(now <= s)
		sum += k * f[s-now];
}

用2进制表示状态,15=1111=四个都选。
用一个数字k记录奇偶(正负)
最后别忘了判断状态是否存在(now <= s),否则会re...

完整代码如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

const int maxn = 1e5+10;

int n,s,c[5],d[5];
long long sum,k,now,f[maxn];

int main() {
	for(int i = 1; i <= 4; i++)
		scanf("%d",&c[i]);
	f[0] = 1;
	for(int i = 1; i <= 4; i++)
		for(int j = c[i]; j <= 100000; j++)
			f[j] += f[j-c[i]];
	scanf("%d",&n);
	while(n--) {
		for(int i = 1; i <= 4; i++)
			scanf("%d",&d[i]);
		scanf("%d",&s);
		sum = f[s];
		for(int i = 1; i <= 15; i++) {
			k = 1;
			now = 0;
			for(int j = 1; j <= 4; j++)
				if((i >> (j-1)) & 1) {
					now += c[j]*(d[j]+1);
					k *= -1;
				}
			if(now <= s)
				sum += k * f[s-now];
		}
		printf("%lld\n",sum);
	}
	return 0;
}

Luogu P1450 [HAOI2008]硬币购物

原文:https://www.cnblogs.com/mogeko/p/12984672.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!