【JZOJ 5461】【NOIP2017提高A组冲刺11.8】购物

Description

X 城的商场中,有着琳琅满目的各种商品。一日,小X 带着小Y 前来购物,小Y 一共看中了n件商品,每一件商品价格为Pi。小X 现在手中共有m个单位的现金,以及k 张优惠券。小X 可以在购买某件商品时,使用至多一张优惠券,若如此做,该商品的价格会下降至Qi。
小X 希望尽可能多地满足小Y 的愿望,所以小X 想要知道他至多能购买多少件商品。

Solution

二分答案,考虑可行性判定,
用可撤销贪心,
先选q前K小的,
那么,对于选了的,把它变成不选的需要代价 pq ,但可以多一个选去的名额
选mid个,看看代价是否小于等于m即可,

复杂度: O(nlog(n)2)

Code

#include 
#include 
#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=100500;
int read(int &n)
{
    int w=1;n=0;char ch=' ';
    for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
    if(ch=='-')ch=getchar(),w=-1;
    for(;ch<='9'&&ch>='0';ch=getchar())n=n*10+ch-48;
    return n=n*w;
}
int n,K,ans;
LL m;
struct qqww
{
    int x,y;
}a[N];
struct qwqw
{
    int v,i;
    friend bool operator<(qwqw q,qwqw w){return q.v>w.v;}
};
priority_queued,d1;
int z[N],TI;
bool PX(qqww q,qqww w){return q.yint mid)
{
    LL ans=0;
    for(;!d.empty();d.pop());
    for(;!d1.empty();d1.pop());
    qwqw t;TI++;
    fo(i,1,min(K,mid))
    {
        ans+=(LL)a[i].y;
        t.v=a[i].x-a[i].y;
        d1.push(t);
        z[i]=TI;
    }
    if(mid<=K)return ans;
    fo(i,K+1,n)
    {
        t.v=a[i].x,t.i=i;d.push(t);
    }
    int q=K+1;
    fo(i,K+1,mid)
    {
        for(;qif(!d1.empty()&&d1.top().v+a[q].yelse 
        {
            t=d.top();d.pop();
            ans+=(LL)t.v;
            z[t.i]=TI;
        }
    }
    return ans;
}
int main()
{
    freopen("shopping.in","r",stdin);
    freopen("shopping.out","w",stdout);
    int q,w;
    read(n),read(K),scanf("%lld",&m);
    fo(i,1,n)read(a[i].x),read(a[i].y);
    sort(a+1,a+1+n,PX);
    int l=0,r=n;
    while(lint mid=(l+r+1)>>1;
        if(OK(mid)<=m)l=mid;
        else r=mid-1;
    }
    printf("%d\n",l);
    return 0;
}

你可能感兴趣的:(可撤销贪心)