【USACO12FEB】Cow Coupons G

题目链接

首先可以确定,在最优解中,$k$张优惠券一定会用光(除非带的钱实在太少)。

于是一开始先选中$c$最小的前$k$只牛。可以证明,最优解中一定包含这些牛,然而优惠券却不一定全部用在它们身上。

假设后来不买这其中的牛$i$,而是转而用优惠价买了这之外的牛$j$,发现$c_j>c_i$绝对是亏的。

假设最后决定用原价买这其中的牛$i$,用腾出来的优惠券买了这之外的牛$j$,发现$p_i+c_j<c_i+p_j$是有可能存在的,此时$p_j-c_j>p_i-c_i$,也即牛$j$的折扣量比牛$i$的折扣量要大,这时候把优惠券用在牛$j$身上是更优的,那这样也是可行的。

接下来继续买牛。如果要买一只牛$i$,可以按原价买,也可以取消已经选中的牛$j$的折扣来用优惠价买牛$i$,二者分别花费$p_i$和$c_i+p_j-c_j$。我们需要每次都选出最便宜的牛,这个用优先队列即可。

用三个优先队列,分别提供当前$p_i,; c_i,; p_i-c_i$的最小的牛。注意别多次买同一只牛。

代码(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
typedef long long LL;
const int N=50000;
const LL inf=2e9+1;

    int n,k;
    LL m;
    
struct Cow{
    LL p,c;    int d;
}a[N+3];

struct cmp_p{IL bool operator()(Cow x,Cow y){return x.p>y.p;}};
struct cmp_c{IL bool operator()(Cow x,Cow y){return x.c>y.c;}};
struct cmp_pc{IL bool operator()(Cow x,Cow y){return x.p-x.c>y.p-y.c;}};

    priority_queue<Cow,vector<Cow>,cmp_p>qp;
    priority_queue<Cow,vector<Cow>,cmp_c>qc;
    priority_queue<Cow,vector<Cow>,cmp_pc>qpc;
    int ans;
    bool v[N+3];

int main(){
    scanf("%d%d%lld",&n,&k,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&a[i].p,&a[i].c);
        a[i].d=i;
        qp.push(a[i]);    qc.push(a[i]);
        
    }
        
    ans=0;
    memset(v,0,sizeof v);
    for(int i=1;i<=k;i++){
        Cow x=qc.top();
        m-=x.c;
        v[x.d]=true;
        qpc.push(x);
        qc.pop();
        
        if(m<0){
            printf("%d",ans);    return 0;
        }
        ans++;
        
    }
    
    for(int i=k+1;i<=n;i++){
        while(v[qp.top().d])    qp.pop();
        while(v[qc.top().d])    qc.pop();
        Cow p=qp.top(),c=qc.top(),pc=qpc.top();
        
        if(p.p<c.c+pc.p-pc.c){
            m-=p.p;
            v[p.d]=true;
            qp.pop();
            
        }
        else {
            m-=c.c+pc.p-pc.c;
            v[c.d]=true;
            qpc.push(c);
            qc.pop();
            qpc.pop();
            
        }
        
        if(m<0)
            break;
        ans++;
        
    }
    
    printf("%d",ans);
    
    return 0;

}
View Code
原文地址:https://www.cnblogs.com/Hansue/p/12917995.html