题目链接
首先可以确定,在最优解中,$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; }