zoukankan      html  css  js  c++  java
  • 洛谷 P2376 [USACO09OCT]津贴Allowance 解题报告

    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)的零用钱。


    一开始的贪心很容易想到要每次先给大钱,如果不够一步步拿小钱补充。

    但最后小钱用完了可能产生浪费,万一大钱浪费一下可以更少呢。又看了看数据范围(N(1<=N<=20)),心想怕不是个搜索。憋了一会儿搜索写不出来。最后看了题解才知道是贪心。

    先说说这个题贪心的思维导向性在哪,没错就是这句话“每一个面额都能整除所有比它大的面额”,是不是感觉又奇怪又违和,感觉用不上??

    一般来讲,遇到这种看起来比较怪的条件,可以尝试这向贪心的方面想一想。哪怕证不出来也没关系,骗点分总不亏撒


    下面正题,贪心策略及证明

    策略

    每一次给钱时,从大钱开始给,但每次给到要浪费钱的一次就不给了,用小一些的钱给。
    给到已经没有小钱了以后,再给怎么也会产生浪费,就从小到大给,用面值尽可能小的钱产生浪费

    总结起来就是一句话:当需要产生浪费时,用面值尽可能小的钱产生

    证明

    命题:大钱产生的浪费一定不比小钱小

    证明:
    任取两个面值的钱分别为(ka,a)(k)是正整数,在当前次还需要支付零用钱至少(X)

    (1) 当浪费大钱(ka)
    (X=b*ka+r)
    则浪费的钱数为(f=ka-r)

    (2)当浪费小钱(a)
    用掉一定的(ka)却不浪费当前次还需要支付的零用钱为(X'=r)
    (X'=b'*a+r')
    则浪费的钱数为(f'=a-r')

    两者做差,(f-f'=(k-1)*a+r'-r)

    由③得,(r'-r=-b'*a)

    (f-f'=(k-b'-1)*a)

    因为(k,b')均为正整数且(k>b'),所以(f-f'>=0)

    命题得证。


    当然,我们肯定不能一次次的枚举每一周,否则会(T)两组。

    考虑对情况进行加速,说是加速,其实也就是存储每周在某种情况下每个钱用了多少张,然后直接统计这种用钱情况可以重复多少次而已。

    写的时候注意细节啊


    Code:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const ll N=23;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    pair <ll ,ll > money[N];
    ll n,c,now,ans,cnt[N],l,r;
    int main()
    {
        scanf("%lld%lld",&n,&c);
        for(ll i=1;i<=n;i++)
            scanf("%lld%lld",&money[i].first,&money[i].second);
        sort(money+1,money+1+n);
        l=1,r=n;
        while(233)
        {
            memset(cnt,0,sizeof(cnt));
            now=c;
            for(ll i=r;i>=l;i--)
            {
                if(!now) break;
                if(now>=money[i].first)
                {
                    cnt[i]=now/money[i].first;
                    if(cnt[i]<=money[i].second)
                         now=now%money[i].first;
                    else
                    {
                        cnt[i]=money[i].second;
                        now=now-money[i].first*cnt[i];
                    }
                }
            }
            if(now)
            {
                ll L=l;
                while(now)
                {
                    if(now<=money[L].first*(money[L].second-cnt[L]))
                    {
                        cnt[L]+=now/money[L].first+(now%money[L].first?1:0);
                        if(!money[L].second) L++;
                        now=0;
                    }
                    else
                    {
                        now-=money[L].first*(money[L].second-cnt[L]);
                        cnt[L]=money[L].second;
                        L++;
                    }
                    if(L>r) break;
                }
            }
            if(!now)
            {
                ll cntt=inf;
                for(ll i=l;i<=r;i++)
                    if(cnt[i])
                        cntt=min(cntt,money[i].second/cnt[i]);
                ans+=cntt;
                for(ll i=l;i<=r;i++)
                {
                    money[i].second-=cntt*cnt[i];
                    if(!money[l].second) l++;
                }
                while(r>=l&&!money[r].second) r--;
            }
            else
                break;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    2018.7.1

  • 相关阅读:
    binder机制理解
    Android 资源目录
    Andriod 构建项目流程
    dpi、ppi 、dp、sp、px、 pt相关概念
    短语、直接短语和句柄
    MySql优化
    java虚拟机内存管理
    redis
    linux——nginx的安装及配置
    linux——高级文本处理命令之wc、cut、sort
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9250415.html
Copyright © 2011-2022 走看看