您的位置:首页 > 其它

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

2017-11-08 20:41 1351 查看
题意: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
;
struct node{int p,q;}a
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: