【洛谷 2376】 [USACO09OCT]津贴Allowance

16 篇文章 0 订阅
9 篇文章 0 订阅

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

题目描述
作为创造产奶纪录的回报,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美分硬币。

【10.12】考试T1

自以为打了个极为正确的贪心然而gg。

数组开成了20000000,原来好像是想开成2000000 ,n明明<=20.。。。。。。。倒也无妨,要命的是多开了一个没用的数组。。。
。。。
QWQ 天让蒟蒻爆零,蒟蒻不得不爆零。

附考试代码:
改掉数组后,只过了四个点。
当时的思路是:边读入边判断,遇到>=c的面额整个直接加入答案,< c的放到数组里存起来,最后将数组从小到大排个序。先选入一个最大的,按住大的不动,再从最小的开始加。没有考虑到答案有可能是数组中最大值的倍数之类的情况。
比如这样:
c=13
处理后的数组:
5 5 5 3 3 2 2 1 1 1
此时的最优解应当是先选入两个5,再从3开始加。这样“花的冤枉钱最少”

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2000000+2;
int a[maxn],b[maxn];
int n,c,v,x,sum;
int main()
{
    //freopen("money.in","r",stdin);
    //freopen("money.out","w",stdout);
    int l=0;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++)//n种面额 
    {
        scanf("%d%d",&v,&x);//v:面额  x:该面额的硬币数 
        if(v>=c) sum+=x;
        else if(v<c)
        {
            for(int k=l+1;k<=l+x;k++) a[k]=v;
            l+=x;
        }
    }
    sort(a+1,a+l+1);
    int r=l,s=0;
    for(int i=1;i<=l;i++)
    {
        if(a[i]+a[r]>=c&&r>i) 
        {
            sum++;
            r--;
            s=0;

        }
        else if(r>i)
        {
            s+=a[i];
            if(s+a[r]>=c)
            {
                sum++;
                r--;
                s=0;

            }
        }
    }
    printf("%d\n",sum);
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20+2;
int n,c,sum;
struct node
{
    int x,v;
}a[maxn];
bool cmp(node a,node b)
{
    return a.v>b.v;
}
int main()
{
    int cnt=0;
    int w,x;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&w,&x);
        if(w>=c) sum+=x;
        else if(w<c)
        {
            a[++cnt].v=w;
            a[cnt].x=x;
        }
    }
    sort(a+1,a+cnt+1,cmp);
    while(1)
    {
        int s=c;
        for(int i=1;i<=cnt;i++)
        {
            if(a[i].v<=s&&a[i].x>0)
            {
                int t=min(s/a[i].v,a[i].x);
                s-=t*a[i].v;
                a[i].x-=t;
            }
        }
        if(s>0)
        {
            for(int i=cnt;i>=1;i--)//从小的开始加
            {
                if(s<=a[i].v&&a[i].x>0)
                {
                    s=0;
                    a[i].x--;
                    break;
                }
            }
        }
        if(s>0) break;
        sum++;
    }
    printf("%d\n",sum);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值