bzoj1042 / HAOI 2008 硬币购物(容斥原理

本文探讨了一种使用容斥原理解决硬币支付组合的问题,具体为在给定4种不同面额硬币的情况下,计算在特定购买次数及金额下可能的支付方式数量。通过将问题转化为求解线性方程的整数解,并结合容斥原理,最终设计出一种高效算法来解决这一问题。
部署运行你感兴趣的模型镜像

Description

硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买s
i的价值的东西。请问每次有多少种付款方法。

Input

第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

Output

每次的方法数

Sample Input

1 2 5 10 2

3 2 3 1 10

1000 2 2 2 900

Sample Output

4

27

分析

嘿嘿嘿容斥终于学有用了。
这题本质上求满足方程 x1c1+x2c2+x3c3+x4c4=sx_1c_1+x_2c_2+x_3c_3+x_4c_4=sx1c1+x2c2+x3c3+x4c4=s 的解,限制条件是 0≤xi≤di0\leq x_i \leq d_i0xidi
假设没有限制条件,这题就是一个完全背包。因此我们想办法往完全背包上靠。于是想到容斥原理。用总方案减去有 xi≥di+1x_i \geq d_i + 1xidi+1 的方案。后面就是一个容斥了。

代码如下

#include <bits/stdc++.h>
#define N 100005
#define LL long long
using namespace std;
int x[5], d[5];
LL f[N], t[17], s, ans;
int bit(int x){
	int s = 0;
	while(x){
		s++;
		x -= x&-x;
	}
	return s;
}
int main(){
	int i, j, n, m, T, cnt;
	for(i = 0; i < 4; i++) scanf("%d", &x[i]);
	scanf("%d", &T);
	f[0] = 1;
	for(i = 0; i < 4; i++)
		for(j = x[i]; j <= 100000; j++) f[j] += f[j - x[i]]; 
	while(T--){
		memset(t, 0, sizeof(t));
		for(i = 0; i < 4; i++) scanf("%d", &d[i]);
		scanf("%d", &s);
		ans = f[s];
		for(i = 0; i < 4; i++) t[1 << i] = (d[i] + 1) * x[i];
		for(i = 1; i < (1 << 4); i++){
			if(!t[i]) t[i] = t[i-(i&-i)] + t[i&-i];
			cnt = bit(i);
			if(s < t[i]) continue;
			if(cnt & 1) ans -= f[s - t[i]];
			else ans += f[s - t[i]];
		}
		printf("%lld\n", ans);
	}
	return 0;
}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值