[USACO12FEB]牛券Cow Coupons(堆,贪心)

[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<=109)。FJ有K张优惠券,使用优惠券购买第i头奶牛时价格会降为Ci(1<=Ci<=Pi),每头奶牛只能使用一次优惠券。FJ想知道花不超过M(1<=M<=1014)的钱最多可以买多少奶牛?

输入输出格式

输入格式:

  • 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.

输入输出样例

输入样例#1:

4 1 7
3 2
2 2
8 1
4 3

输出样例#1:

3

说明

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.

堆模拟反悔操作

很容易发现直接贪心是错误的,因为我们有总钱数的限制。
那么我们可不可以通过调整假的贪心策略来获得正确答案呢?
先贪心地拿最小的k个优惠价,然后考虑怎么反悔。
对于两头牛\(i,j\),假设\(i\)用了优惠券,\(j\)没有用,什么情况下会使\(j\)用优惠券\(i\)不用更优呢?很简单:\(c[i]+p[j]>p[i]+c[j]\)。用一个堆维护用优惠券的牛,令一个堆维护还未选择的牛。每次考虑未选择的牛是用原价买还是“反悔”。
不过自己还有一个疑问,每次钱不够的时候就能够break掉了吗?感觉仔细思考了一下并不可以。希望能够解答

#include<bits/stdc++.h>
#define lll long long
using namespace std;
lll read(){
    lll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*w;
}
const lll N=50010;
lll n,k,m,ans;
bool vis[N];
struct node{
    lll p,c,v;
}f[N];
priority_queue< pair<int,int> >q1,q2;
bool cmp(node p,node q){return p.c<q.c;}
int main(){
    n=read();k=read();m=read();
    for(lll i=1;i<=n;i++)f[i].p=read(),f[i].c=read(),f[i].v=f[i].p-f[i].c;
    sort(f+1,f+1+n,cmp);
    for(lll i=1;i<=k;i++){
        if(m<f[i].c){cout<<i-1;return 0;}
        m-=f[i].c;q1.push(make_pair(f[i].v,i));
    }ans=k;
    for(lll i=k+1;i<=n;i++)q2.push(make_pair(-f[i].p,i));
    while(m&&ans!=n){
        lll i=q2.top().second;q2.pop();
        lll j=q1.top().second;q1.pop();
        if(f[j].c+f[i].p>f[i].c+f[j].p){
            if(m<f[j].v+f[i].c)break;
            q1.push(make_pair(f[i].v,i));
            m-=f[j].v+f[i].c;ans++;
        }
        else {
            if(m<f[i].p)break;
            q1.push(make_pair(f[j].v,j));
            m-=f[i].p;ans++;
        }
    }cout<<ans<<endl;
}
posted @ 2018-10-05 23:05  Frozen_Heart  阅读(367)  评论(2编辑  收藏  举报