硬币的面值 题解(不完全)

硬币的面值 题解(不完全)


题目

小A有n枚硬币,现在要买一样不超过m元的商品,他不想得到找钱(多脏啊),同时又不想带太多的硬币,且硬币可以重复,现在已知这n枚硬币的价值,请问最少需要多少硬币就能组合成所有可能的价格?

输入格式

第一行两个数:n、m。
下一行,共n个数字,表示硬币的面值。

输出格式

一行一个数,表示最少需要多少硬币。如果无解请输出“No answer!!!”

输入输出样例

输入:

5 31
1 2 8 4 16

输出:

6

思路

首先将各面值的硬币从小到大存在value数组中,此时假设前i 种硬币使用最少的数目组成的最大的数mx元,且满足mx<value[i+1]的条件,此时,如果需要增加mx的值,则将value[i+1]考虑进运算,
即:\(f(m)=min \lbrace \quad f(m-value[i]) \quad|\quad value[i]<=m\rbrace+1, m>0\)
m从小到大增加, 判断的临界点就是m+value[i]>value[i+1]时,实际运用中,使用贪心的方法,mx+k*value[i]>value[i+1], mx+=k*value[i],每次使用刚刚好的value[i], 且实际如果相等且不考虑精度问题,下面是个人理解k*value[i]是为了实现value[i]-1value[i+1]-1之间的跨越(因为mx<value[i]),且k尽可能的小,所以(value[i+1]-1-mx)/value[i]进行一个放缩,分子-1,结果+1,ORZ,我不知道。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;  

typedef long long ull;
ull value[2000004],cnt=0,mx=0;

int main(){
	ull n,m;
	scanf("%llu%llu",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%llu",&value[i]);
 	}

 	value[n+1]=m;
 	sort(value+1,value+1+n+1);
 	
	if(value[1]!=1){ printf("No answer!!!"); return 0;}

 	for(int i=1;i<=n;++i){
 		if(mx<value[i+1]-1){
			long long k=(value[i+1]-2-mx)/value[i]+1;
			cnt+=k;
			mx+=k*value[i];
			if(mx>=m){
				printf("%llu\n",cnt);
				return 0;
			}
		}
 	}
	printf("%llu",cnt+1);
	return 0;

}
posted @ 2021-10-27 23:54  hertz-01  阅读(289)  评论(0)    收藏  举报