牛券

传送门

这道题很神奇啊……

我们一开始无论是贪心取最小还是差价最大都不对,后来发现这其实是一道带有反悔性质的贪心……

我们首先维护前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('
')

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
",i-1),exit(0);
    if(i == n) printf("%lld
",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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/captain1/p/9853655.html