题目背景

作为学习刻苦、成绩优秀的回报,妈妈决定开始每个星期给杀马特一点零花钱。

题目描述

作为创造产奶纪录的回报,Farmer John决定开始每个星期给Bessie一点零花钱。

FJ有一些硬币,一共有N (1 <= N <= 20)种不同的面额。每一个面额都能整除所有比它大的面额。

他想用给定的硬币的集合,每个星期至少给Bessie某个零花钱的数目C (1 <= C <= 100000000)。请帮他计算他最多能支付多少个星期的零花钱。

输入格式

第1行: 两个由空格隔开的整数: N 和 C;

第2到第N+1行: 每一行有两个整数表示一个面额的硬币:硬币面额V (1 <= V <= 100,000,000)拥有的该面额的硬币数B (1 <= B <= 1,000,000)。

(感谢fyszzhouzj,现错误已改正)

输出格式

第1行: 一个单独的整数,表示最多能给支付多少个星期至少为C的零用钱。

输入输出样例

输入 #1
3 6
10 1
1 100
5 120
输出 #1
111

说明/提示

【样例说明】

杀马特的妈妈想要每个星期给杀马特六美分。他有100个1美分硬币,120个5美分硬币,和一个10美分硬币。他妈妈可以在一个星期超额付给杀马特一个10美分硬币,然后接下来的10个星期每星期付给杀马特两个5美分硬币。最后100个星期每星期付给杀马特一个1美分硬币跟一个5美分硬币。

思路

证明

②如果当前这个值可以被选,就选到不能再选这个值为止(就酱。。。)

代码

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

const int N=50;

int n,c,ans;

struct no {
	int buy,nu;
} a[N];

bool cmp(no x,no y) {
	return x.buy>y.buy;
}

int main() {
	scanf("%d%d",&n,&c);
	for(int i=1; i<=n; i++)
		scanf("%d%d",&a[i].buy,&a[i].nu);
	sort(a+1,a+1+n,cmp);
	int now=1, en=n;
	while(a[now].buy>=c) {
		ans+=a[now].nu;
		now++;
	}
	while(1) {
		int ka=c;
		for(int i=now; i<=n; i++)
			while (ka>=a[i].buy&&a[i].nu&&ka>0) {
				ka-=a[i].buy;
				a[i].nu--;
			}
		if(ka>0)
			for(int i=n; i>=now; i--) {
				if(a[i].buy>=ka&&a[i].nu) {
					a[i].nu--;
					ka-=a[i].buy;
					break ;
				}
			}
		if(ka>0)
			break;
		ans++;
	}
	printf("%d\n",ans);
	return 0;
}
01-06 07:49