Allowance 贪心

放题:
As a reward for record milk production, Farmer John has decided to start paying Bessie the cow a small weekly allowance. FJ has a set of coins in N (1 <= N <= 20) different denominations, where each denomination of coin evenly divides the next-larger denomination (e.g., 1 cent coins, 5 cent coins, 10 cent coins, and 50 cent coins).Using the given set of coins, he would like to pay Bessie at least some given amount of money C (1 <= C <= 100,000,000) every week.Please help him ompute the maximum number of weeks he can pay Bessie.

Input

  • Line 1: Two space-separated integers: N and C

  • Lines 2…N+1: Each line corresponds to a denomination of coin and contains two integers: the value V (1 <= V <= 100,000,000) of the denomination, and the number of coins B (1 <= B <= 1,000,000) of this denomation in Farmer John’s possession.

Output

  • Line 1: A single integer that is the number of weeks Farmer John can pay Bessie at least C allowance

Sample Input
3 6
10 1
1 100
5 120

Sample Output
111

拿到题就知道是贪心,但我不知道知道怎么贪心,在我看来,每种硬币的数据范围是1e6,有20种,我计算是2e7,for循环一般最多跑1e8的数据,就没敢往逐个硬币去贪心,以为是硬币种类上的贪心。但想来想去,都不对。
写了好几次,都崩了,才考虑逐个去贪心。
思路:先找到大于每周工资的硬币,这些可以先给了,因为这些硬币不用和其他硬币拼凑就比每周工资大(这一步预处理可以节省一定的时间)。然后怎么去取,我考虑是从大的和小的拼凑,但无奈太菜了,又错了几次,只好看了下题解。根据大佬的思路,我们只要从大往小取,有等于每周工资的,先给了,使之不超过每周工资,再从小到大取,若超过每周工资就可以给了。这样子就可以巧妙的完成了我原先大小拼凑的思路,我只能说学到了,自己还是太菜了,还要好好学习。

代码如下:

//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define fo1(a,b) for(int a=0;a<b;++a)
#define fo2(a,b) for(int a=1;a<=b;++a)
#define lowbit(a) a&(-a)
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e5+5;
const int mod=1e9+7;
struct node
{
    int mon,num;
    bool operator < (const node b) const{
        return mon<b.mon;
    }
}cnt[25];
int main()
{
    int n,m;
    cin>>n>>m;
    fo2(i,n)
    scanf("%d%d",&cnt[i].mon,&cnt[i].num);
    sort(cnt+1,cnt+1+n);
    int cnr=n;
    int sum=0,ans=0;
    for(int i=n;i>=1;--i){    //预处理,超额工资就先给了
        if(cnt[i].mon>=m){
            ans+=cnt[i].num;
            cnr--;
        }
        else
            sum+=cnt[i].num;
    }
    while(sum){
        int t=m;
        for(int i=cnr;i>=1;--i){
            if(!cnt[i].num)
                continue;
            if(sum>0){ //在取得最接近每周工资的所用的硬币个数
                       //和实际所有的硬币个数中取最小值
                int te=min(t/cnt[i].mon,cnt[i].num);
                t-=te*cnt[i].mon;
                sum-=te;
                cnt[i].num-=te;
            }
            if(t<=0)    //满足条件跳出
                break;
        }
        if(t>0)
            for(int i=1;i<=cnr;++i){
                if(cnt[i].num){  //这里的循环也可以用上面的那种方式做,
                                 //可以节省时间
                    while(t>0&&cnt[i].num){
                        t-=cnt[i].mon;
                        sum--;
                        cnt[i].num--;
                    }
                if(t<=0)
                    break;
                }
            }
        if(t<=0)
            ans++;
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值