P2376 [USACO09OCT]津贴Allowance
题目背景
作为学习刻苦、成绩优秀的回报,妈妈决定开始每个星期给杀马特一点零花钱。
题目描述
作为创造产奶纪录的回报,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)。
输出格式:
第1行: 一个单独的整数,表示最多能给支付多少个星期至少为C的零用钱。
输入输出样例
输入样例#1:
3 6 10 1 1 100 5 120
输出样例#1:
111
说明
【样例说明】
杀马特的妈妈想要每个星期给杀马特六美分。他有100个1美分硬币,120个5美分硬币,和一个10美分硬币。他妈妈可以在一个星期超额付给杀马特一个10美分硬币,然后接下来的10个星期每星期付给杀马特两个5美分硬币。最后100个星期每星期付给杀马特一个1美分硬币跟一个5美分硬币。
分析:贪心。
因为每一个面额都能整除所有比它大的面额。所以小的面额的硬币一定可以凑成大的硬币。
所以我们可以先按照货币面值大小排序,从大到小开始,如果比 c 大,直接加上这个面值的硬币的数量,如果不能达到,拿小的凑。
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 struct moy{ 7 int x,y; 8 bool operator < (const moy a) const 9 { 10 return x < a.x; 11 } 12 }t[25]; 13 int h[25]; //已经使用的硬币数 14 int n,c,p,ans; 15 16 int main() 17 { 18 scanf("%d%d",&n,&c); 19 for (int i=1; i<=n; ++i) 20 scanf("%d%d",&t[i].x,&t[i].y); 21 22 sort(t+1,t+n+1); 23 p = n+1; 24 while (t[--p].x>=c) ans += t[p].y; 25 while (1) 26 { 27 int s = c; //s剩余的钱 28 for (int i=p; i>=1; --i) 29 { 30 int cnt = min(t[i].y, s/t[i].x); 31 s -= t[i].x*cnt; //cnt使用硬币的数量 32 h[i] = cnt; 33 } 34 if (s>0) 35 for (int i=1; i<=p && s>0; ++i) 36 if (t[i].y>h[i]) s -= t[i].x, h[i]++; 37 if (s<=0) 38 { 39 int cnt = 1e9; 40 for (int i=1; i<=p; ++i) 41 if (h[i]) cnt = min(cnt,t[i].y/h[i]); //cnt有多少可以这样,搭配的组合 42 ans += cnt; 43 for (int i=1; i<=p; ++i) 44 if (h[i]) t[i].y -= cnt*h[i]; 45 } 46 else break; 47 } 48 printf("%d",ans); 49 return 0; 50 }
时间: 2024-10-03 03:47:02