洛谷 P2376 [USACO09OCT]津贴Allowance

来源:互联网 发布:淘宝流量怎么提高 编辑:程序博客网 时间:2024/04/28 14:10

洛谷 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)。

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

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

输入输出样例

输入样例#1:

3 610 11 1005 120

输出样例#1:

111

说明

【样例说明】

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


题解

贪心

先把面额超过或等于C(我的代码里面是m)的直接当做一个星期的零花钱,其余的加入数组,按面额排序

我先将一个星期的零花钱尽量用大面额的钱填充(即从大面额到小面额的钱来填充),如果还有剩余,那么就用1张剩余的最小面额的钱填充即可(因为题目上说过每一个面额都能整除所有比它大的面额,如果还有剩余的话,最小面额的钱最多只会被拿一次,因为所有超过它的值的都已经在用最小面额的钱填充的时候填充过了),最后就是查询一下,能满足这次分配的方案数,并对储存各种面额的钱的数量的数组进行调整


代码

#include<cstdio>#include<cstdlib>using namespace std;int n,m,x,y,tot,ans;int a[25],b[25],use[25];int readln(){    int x=0;    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while ('0'<=ch&&ch<='9') x=x*10+ch-48,ch=getchar();    return x;}void qsort(int l,int r){    int i=l,j=r,mid=a[rand()%(r-l+1)+l],t;    do {        while (a[i]<mid) i++;        while (a[j]>mid) j--;        if (i<=j) {            t=a[i];a[i]=a[j];a[j]=t;            t=b[i];b[i]=b[j];b[j]=t;            i++;j--;        }    } while (i<=j);    if (i<r) qsort(i,r);    if (l<j) qsort(l,j);}int min(int x,int y){return x<y?x:y;}int main(){    n=readln();m=readln();    for (int i=1;i<=n;i++)    {        x=readln();y=readln();        if (a[i]>=m) ans+=y;else a[++tot]=x,b[tot]=y;    }    qsort(1,tot);    while (true)    {        int ret=m,t;        for (int i=tot;i>0;i--)        {             t=min(b[i],ret/a[i]);             ret-=a[i]*t,use[i]=t;        }        if (ret>0) for (int i=1;i<=tot&&ret>0;i++) if (b[i]>use[i]) ret-=a[i],use[i]++;        if (ret<=0)        {            t=1e9;            for (int i=1;i<=tot;i++) if (use[i]) t=min(t,b[i]/use[i]);            ans+=t;            for (int i=1;i<=tot;i++) if (use[i]) b[i]-=t*use[i];        }        else break;    }    printf("%d",ans);    return 0;}
原创粉丝点击