JZOJ5461. 【NOIP2017提高A组冲刺11.8】购物 贪心+堆

来源:互联网 发布:c语言计算1到n的乘积 编辑:程序博客网 时间:2024/06/10 16:55

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

由于是NOIP模拟赛,于是没有去想堆方面的玩意儿,没想到听stdcall说堆是NOIP的考点,不过说的也对,去年T2不就考了吗。。

回归正题,这题的话正常贪心非常不好想,可以用堆处理。
考虑先把qi最小的k个先取出,然后往堆中插入pi-qi,表示需要花费pi-qi得到一张优惠券,然后再开两个堆,分别存储未买的商品中最小的p和q,然后每次看是重新得到一张优惠券更优还是直接买更优秀,更新到m<0为止。

注意其实贪心堆的做法的一个宗旨就是撤销操作,把已经做过的操作撤销来达到最优方案,这样就比较好看出是否需要堆来贪心。

#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define mp make_pair#define pair pair<int,int>using namespace std;typedef long long ll;const int N=5e5+5;int n,k;ll m;bool vis[N];struct node{int p,q;}a[N];priority_queue<pair>q1,q2;priority_queue<int>q3;bool cmp(node a,node b){    return a.q<b.q;}int main(){    freopen("shopping.in","r",stdin);    freopen("shopping.out","w",stdout);    scanf("%d%d%lld",&n,&k,&m);    fo(i,1,n)scanf("%d%d",&a[i].p,&a[i].q);     sort(a+1,a+n+1,cmp);    int ans=0;    fo(i,1,k)    if (a[i].q<=m)     {        m-=a[i].q,ans++;        vis[i]=1;        q3.push(-(a[i].p-a[i].q));    }    else     {        printf("%d",ans);        return 0;    }    fo(i,k+1,n)     q1.push(mp(-a[i].p,i)),q2.push(mp(-a[i].q,i));    fo(i,k+1,n)    {        while (vis[q1.top().second]) q1.pop();        while (vis[q2.top().second]) q2.pop();        if (-q1.top().first<-q2.top().first-q3.top())        {            pair s=q1.top();            q1.pop();            int x=-s.first,y=s.second;            if (x>m) break;            m-=x;vis[y]=1;        }        else        {            pair s=q2.top();q2.pop();            int x=-s.first-q3.top();            int y=s.second;            q3.pop();            if (x>m) break;            m-=x;            vis[y]=1;            q3.push(-(a[y].p-a[y].q));        }        ans++;    }    printf("%d\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击