NKOJ 1243 【USACO OCT09】零用钱

NKOJ 1243 【USACO OCT09】零用钱

思路

  • 读题:题目中有一句话值得注意

    每一个面额都能整除所有比它大的面额。

    通过这句话实际上可以知道,所有小面额都可以凑出大面额。

  • 对初步想法的延伸:既然小面额能凑出大面额,当我有的钱数不足以发刚好 \(c\) 元时,浪费大面额一定比浪费小面额划算,如:我要发六块,我有一张十块和两张五块,两张一块,我在有十块的情况下一定不会发两张五块,因为五块的可以和一块的凑。

  • 既然如此我们不妨模拟每一次发钱。

    • 先尝试凑正好 \(c\) 元,如果当前面额在不超过 \(c\) 的情况下能凑就拿,不然就下一个面额接着拿。
    • 如果不能刚好凑够 \(c\) 元,就从小面额开始找正好超过一点点的面额,如果找不到,就说明钱全部被拿完了,只能退出。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
int n,c,ans=0;
struct node{int v,num;}arr[25];
bool cmp(node x,node y){return x.v>y.v;}
int main(){
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++) scanf("%d%d",&arr[i].v,&arr[i].num);
	sort(arr+1,arr+1+n,cmp);
	while(1){
		int now=c;
		for(int i=1;i<=n;i++){
			while(arr[i].v<=now&&arr[i].num>0) now-=arr[i].v,arr[i].num--;
		}
		if(now>0){
			for(int i=n;i>=1;i--){
				if(arr[i].v>=now&&arr[i].num>0){
					now-=arr[i].v,arr[i].num--;
					break;
				}
			}
		}
		if(now>0) break;
		ans++;
	}
	printf("%d",ans);

	return 0;
}
posted @ 2025-04-13 15:48  hsr_ray  阅读(3)  评论(0)    收藏  举报