官方题解:
There are several different ways to approach this problem.
One of them stems from the initial idea of picking the lowest-cost cow each time: use all coupons on the cheapest
cows, then buy as many cows as possible without coupons. However, this doesn’t quite work: if several cows are very cheap with or without a coupon, and other cows are cheap with a coupon but very expensive without one, we can intuitively see that we would like to use our coupons on the more expensive cows. This leads to the idea of “revoking” a coupon: for cow i, we can pay (Pi−Ci) in order to regain one of our coupons (because we are now buying cow i at the “expensive” price).
After purchasing as many cows as possible with coupons, we store their (Pi−Ci) values in a heap.
To purchase a remaining cow j, we can either pay Pj or Cj+ (Pi−Ci), where cow i is the top cow in our heap.
This ensures we are always using exactly as many coupons as we can.
For each cow we add to our lineup, we are greedily paying the minimum possible amount for it, so this solution is clearly optimal.
题解大意:
先选出k头按c花费最小的牛,将这k头牛节省下的钱依次存入小根堆st。对于其他牛j,买牛j的最小花费 = min (Pj,(Pi-Ci)+ Cj) ,st实际就是在维护(Pi-Ci)组成的序列, 很明显(Pi-Ci)取st的堆顶时最小。由此得出买牛j的最小花费= min(Pj,st.top()+Cj).
因此还需要维护Pj组成的一个堆,Cj组成的一个堆。每次都选择两种堆中更优的堆顶。用multiset实现堆,操作和优先队列类似。
code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct Node{
int val , id ;
bool operator < (Node no1) const{
if(val!=no1.val) return val < no1.val ;
else return id < no1.id ;
}
};
multiset<Node> ch , ep;
multiset<int> st;
int n , m , k ;
bool vis[50005] ;
int p[50005], c[50005] ;
signed main()
{
//freopen("in","r",stdin);
scanf("%lld%lld%lld",&n,&k,&m);
for(int i = 0 ; i < k ; i++){
st.insert(0);
}
for(int i = 0 ; i < n ; i++) {
scanf("%lld%lld",&p[i],&c[i]);
ch.insert({c[i],i});
ep.insert({p[i],i});
}
int ans = 0 ;
while(ans < n && m > 0){
while(!ch.empty()&&vis[(*ch.begin()).id])ch.erase(ch.begin());
while(!ep.empty()&&vis[(*ep.begin()).id])ep.erase(ep.begin());
Node C = *ch.begin() , P = *ep.begin();
if(C.val + *st.begin() < P.val){
m = m - (C.val + *st.begin()) ;
vis[C.id] = true;
ch.erase(ch.begin());
st.erase(st.begin());
st.insert(p[C.id] - c[C.id]);
}else{
m = m - P.val ;
vis[P.id] = true;
ep.erase(ep.begin());
}
if(m>=0) ans++;
}
cout << ans << endl ;
return 0 ;
}