[USACO12FEB] 牛券Cow Coupons

来了来了,贪心来了。话说写不出来题就去贪心啦~

题目描述

Farmer John needs new cows! There are N cows for sale (1 <= N <= 50,000), and FJ has to spend no more than his budget of M units of money (1 <= M <= 10^14). Cow i costs P_i money (1 <= P_i <= 10^9), but FJ has K coupons (1 <= K <= N), and when he uses a coupon on cow i, the cow costs C_i instead (1 <= C_i <= P_i). FJ can only use one coupon per cow, of course.

What is the maximum number of cows FJ can afford?

FJ准备买一些新奶牛,市场上有N头奶牛(1<=N<=50000),第i头奶牛价格为Pi(1<=Pi<=10^9)。FJ有K张优惠券,使用优惠券购买第i头奶牛时价格会降为Ci(1<=Ci<=Pi),每头奶牛只能使用一次优惠券。FJ想知道花不超过M(1<=M<=10^14)的钱最多可以买多少奶牛?

输入输出格式

输入格式:

* Line 1: Three space-separated integers: N, K, and M.

* Lines 2..N+1: Line i+1 contains two integers: P_i and C_i.

输出格式:

* Line 1: A single integer, the maximum number of cows FJ can afford.

说明

FJ has 4 cows, 1 coupon, and a budget of 7.

FJ uses the coupon on cow 3 and buys cows 1, 2, and 3, for a total cost of 3 + 2 + 1 = 6.


背景

  当我开始写题解的时候,绝对是我DP写挂了,来换心情的。。。。

  大概是前天的时候,学长讲了这道题,昨天写了进阶版的题解。

  有人跟我说不太懂可反悔的贪心是什么,所以我就来整理一下。


可反悔的贪心

  贪心大家都了解吧,就是选择当前的最优策略,整合后形成最优解。

  但是这个时候我们可以发现一个问题:

      如果局部最优解与形成整体最优解的情况矛盾怎么办?

  举个例子具体理解一下,

    a有两种选择x1,x2;b有两种选择,y1,y2

    假设,让a满足最优的解法是选择x1,但是使得整体最远的解法则是在a处选择x2.

  那么我们怎么样才能使得这种策略能够被选到呢?

  搜索算法自然是可以做到的,但是一旦数据范围变大就炸掉了。

  那么究竟该怎么办呢?

  我们来仔细思考一下,阻挡我们使用贪心的最大问题是什么?

      是不是一旦局部最优解不是整体最优解,就完全错误?    

      那么假设我们可以时光回溯,回到错误的点修改答案是不是就正确了呢?

  好的,那么只要我们记录一下当前策略与未来策略的差值,当出现问题的时候,直接修改就ok了。

  关于实现问题,就是使用堆栈处理,一般是大根堆。

  这就是可修改的贪心。


 

思路分析

  在这道题,我们可以发现,对于每一头牛来说,其实都有两个状态。

      那么我们就可以把两个状态当作是当前可以选择的策略,用优惠券和不用优惠券。

  接下来跑一次可反悔的贪心就ok。

  然后我们就会发现一个问题, 优惠券是有数量的。

  这个也好处理,我们优先处理使用优惠券之后最便宜的几头牛,然后选择剩下的牛中不用券最便宜的。

  之后判断要不要将用过的一张券转用给一头新的牛。

  思路就是开一个大根堆,然后依次push进去p[i] - c[i]

  取出使用即可。


 

代码实现

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;

int n,k;
ll m;
struct ss{
    ll p,c;
}cow[50001];
priority_queue<long long,vector<long long>,greater<long long> > q;

int cmp(ss a,ss b) {
    return a.c<b.c;
}

int cmmp(ss a,ss b) {
    return a.p<b.p;
}

int main()
{
    scanf("%d%d%lld",&n,&k,&m);
    for(int i=1;i<=n;i++) 
        scanf("%lld%lld",&cow[i].p,&cow[i].c);
    sort(cow+1,cow+n+1,cmp);
    ll sum=0;
    for(int i=1;i<=k;i++) {
        sum+=cow[i].c;
        if(sum>m) {
            cout<<i-1<<endl;
            return 0;
        }
        q.push(cow[i].p-cow[i].c);
    }
    sort(cow+k+1,cow+n+1,cmmp);
    for(int i=k+1;i<=n;i++) {
        if(cow[i].p-cow[i].c>q.top()) {
            sum+=q.top();
            q.pop();
            q.push(cow[i].p-cow[i].c);
            sum+=cow[i].c;
        }
        else 
            sum+=cow[i].p;
        if(sum>m) {
            cout<<i-1<<endl;
            return 0;
        }
    }
    cout<<n<<endl;
    return 0;
}

 

posted @ 2019-07-20 09:56  鸽子咕  阅读(183)  评论(0编辑  收藏  举报