洛谷P2001【硬币的面值】

本文深入探讨了一种解决硬币找零问题的算法,详细分析了如何通过模拟过程找到构成任意金额所需的最少硬币数量。特别关注了硬币面额序列的特性,确保能够覆盖所有可能的价格组合。

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

其实这道题就按照题面意思直接模拟一下就好喇!

很显然如果给定硬币的最小值大于1则输出"No answer!!!"因为这样子就无法取到1这个面值了。

先证明一下这一点:如果目前状态可取前 xxx 价格,且当前取了一个面额为 aaa 的硬币,要想构成前 x+ax + ax+a 的所有价格,必须仅当 x≥a−1x \ge a - 1xa1 时成立—>

证:若 x<a−1x < a - 1x<a1, 则我们取最小的 x+1x + 1x+1,它必须由 x+1−ax + 1 - ax+1a 得到,而 x<a−1x < a - 1x<a1,故 x+1−a<0x + 1 - a < 0x+1a<0,由于不存在小于0的状态,故原命题成立。

假设当前状态,前 iii 种硬币已经用最小的硬币数 ansansans 构成最大的可行价格 tottottot ,那么如果当前 tot≥ai+1−1tot \ge a_{i + 1} - 1totai+11,那么就可以直接 i++i + +i++;否则累加,使 tot=tot+aitot = tot + a_{i}tot=tot+aitot≥ai+1−1tot \ge a_{i + 1} - 1totai+11 , 同时每次 ansansans ++++++ 。因为我们在每一步都满足 tot≥ai+1−1tot \ge a_{i + 1} - 1totai+11 , 所以每次 i++i++i++ 时,我们都可以放心操作当前的 tot+aitot + a_{i}tot+ai 操作。特别的,当 iii 等于1时,如果 tot(=0)<a1−1tot(=0) < a_{1} - 1tot(=0)<a11 , 即 a1>1a_{1} > 1a1>1时,不能满足条件,因而无答案,这里解释了第二段的显然结论。

关于这个累加,由于数据范围很大,我们很容易被卡(如都是1),所以我们先算出 tottottot 加上多少个 aia_{i}ai 才能大于等于 ai+1a_{i + 1}ai+1,即个数 k=(ai+1−2−tot)÷ai+1k = (a_{i + 1} - 2 - tot) \div a{i} + 1k=(ai+12tot)÷ai+1 ,再 tot=tot+k∗aitot = tot + k * a_{i}tot=tot+kaians=ans+kans = ans + kans=ans+k, 用 O(1)的时间解决了问题。同时我们把 an+1a_{n + 1}an+1 赋值为 mmm , 助于判停。

最后注意一点:如果 tottottot 刚好等于 m−1m - 1m1 ,并结束了循环,此时我们要在循环外输出 ans+1ans + 1ans+1 , 以应对此特殊情况。

下面我来贴一下代码—>

#include <cstdio>
#include <algorithm>
#define ll long long
#define inf 1023456789

using namespace std;

ll n, m, a[2000005], ans, tot;

int main(){
	scanf("%lld%lld",&n,&m);
	for(int i = 1; i <= n; i++)
		scanf("%d",&a[i]);
	sort(a + 1, a + n + 1);
	if(a[1] != 1) {
		printf("No answer!!!\n");
		return 0;
	}
	a[n + 1] = m;
	for(int i = 1; i <= n; i++){
		if(tot < a[i + 1] - 1){
			ll k = (a[i + 1] - 2 - tot) / a[i] + 1;
			tot += a[i] * k;
			ans += k;
			if(tot >= m){
				printf("%lld\n",ans);
				return 0;
			}
		}
	}
	printf("%lld\n",ans + 1);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值