牛券
这道题很神奇啊……
我们一开始无论是贪心取最小还是差价最大都不对,后来发现这其实是一道带有反悔性质的贪心……
我们首先维护前k个优惠值,我们如果能取肯定是买这些的,如果已经到了上限就直接结束。之后,我们考虑后面的物品,有可能选择用优惠价买这些物品更优,所以我们提供返回操作,维护一个原价的小根堆,再维护一个差值小根堆,每次取堆顶元素比较,如果更优的话就进行替换,否则我们就以原价购买这件东西,这样贪心即可。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') using namespace std; typedef long long ll; const int M = 100005; const ll INF = 100000000000009; ll read() { ll ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct node { ll p,c; }a[M]; ll n,m,k,ans,sum; priority_queue<ll,vector<ll>,greater<ll> > q; bool cmpc(node x,node y) { return x.c < y.c; } bool cmpp(node x,node y) { return x.p < y.p; } int main() { n = read(),k = read(),m = read(); rep(i,1,n) a[i].p = read(),a[i].c = read(); sort(a+1,a+1+n,cmpc); rep(i,1,k) { sum += a[i].c; if(sum > m) printf("%d\n",i-1),exit(0); if(i == n) printf("%lld\n",n),exit(0); q.push(a[i].p - a[i].c); } sort(a+1+k,a+1+n,cmpp),ans = k; rep(i,k+1,n) { ll cur = (!q.empty()) ? q.top() : INF; if(a[i].p - a[i].c > cur) sum += cur + a[i].c,q.pop(),q.push(a[i].p - a[i].c); else sum += a[i].p; if(sum > m) break; else ans++; } printf("%lld\n",ans); return 0; }
当你意识到,每个上一秒都成为永恒。