[Luogu P1450] [BZOJ 1042] [HAOI2008]硬币购物

本文探讨了一种硬币购物问题的算法解决方案,通过预处理无限制情况并结合容斥原理,有效地计算了在特定条件下购买商品的支付方式数量。输入包括不同面值硬币的数量和购买次数,输出为每次购物的可能支付方法数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷传送门
BZOJ传送门

题目描述

硬币购物一共有 4 4 4种硬币。面值分别为 c 1 , c 2 , c 3 , c 4 c_1,c_2,c_3,c_4 c1,c2,c3,c4。某人去商店买东西,去了 t o t tot tot次。每次带 d i d_i di c i c_i ci硬币,买 s i s_i si的价值的东西。请问每次有多少种付款方法。

输入输出格式

输入格式:

第一行 c 1 , c 2 , c 3 , c 4 , t o t c_1,c_2,c_3,c_4,tot c1,c2,c3,c4,tot 下面 t o t tot tot d 1 , d 2 , d 3 , d 4 , s d_1,d_2,d_3,d4,s d1,d2,d3,d4,s

输出格式:

每次的方法数

输入输出样例

输入样例#1:
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900
输出样例#1:
4
27

说明

d i , s ≤ 100000 d_i,s\le 100000 di,s100000

t o t &lt; 1000 tot&lt;1000 tot<1000

解题分析

先预处理出无限制的情况, 然后钦定先选 d i + 1 d_i+1 di+1枚, 剩下的所有方案都是不满足的, 减去即可。

这样搞会算重, 多减去既选 d i + 1 d_i+1 di+1 c i c_i ci d i + 1 + 1 d_{i+1}+1 di+1+1 c i + 1 c_{i+1} ci+1这类情况, 因此我们容斥掉即可。

代码如下:

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 100500
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
ll sum[MX << 1], ans;
int c[5], tot, d[5], mon;
void DFS(R int now, R int typ, R int inc)
{
	if(inc > mon) return;
	if(now == 5) return ans += inc ? typ * sum[mon - inc] : 0, void();
	DFS(now + 1, typ, inc);
	DFS(now + 1, typ * -1, inc + c[now] * (d[now] + 1));
}
int main(void)
{
	sum[0] = 1;
	in(c[1]), in(c[2]), in(c[3]), in(c[4]), in(tot);
	for (R int i = 0; i <= 100000; ++i) sum[i + c[1]] += sum[i];
	for (R int i = 0; i <= 100000; ++i) sum[i + c[2]] += sum[i];
	for (R int i = 0; i <= 100000; ++i) sum[i + c[3]] += sum[i];
	for (R int i = 0; i <= 100000; ++i) sum[i + c[4]] += sum[i];
	W (tot--)
	{
		in(d[1]), in(d[2]), in(d[3]), in(d[4]), in(mon);
		ans = sum[mon];
		DFS(1, 1, 0);
		printf("%lld\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值