ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF335F】 Buy One, Get One Free(反悔贪心)

2022-07-22 18:35:28  阅读:136  来源: 互联网

标签:Buy Get int CF335F 2x 反悔 物品 include 免费


原题链接

题意

有 \(n\) 个物品,你每购买一个物品可以免费获得一个价格严格小于它的物品,求得到所有物品的最小代价。

数据范围

\(1 \leq n \leq 5 \times 10^5\)

思路

考虑贪心,最朴素的想法就是从大到小枚举物品,并且免费获得第一个价格严格小于它的物品。但很显然这样的想法是错误的,原因在于拿走最大的可以免费的物品,可能会导致后面浪费了一次免费的机会,此时有可能买下这个物品更优,可以考虑反悔贪心。

可以用一个小根堆维护当前所免费的物品,考虑当前有两个价值为 \(x\) 的物品,可以做以下两种选择:

1.两个物品都直接购买,代价为 \(2x\)。

2.对于之前的物品,有一个策略是买了 \(a\) 免费 \(b\)(此时满足 \(a>b>x\)),此时将这个决策反悔,即买 \(a\) 和 \(b\),免费 \(2x\)。此时的就相当于多买了一个 \(b\)。代价为 \(b\)。

若 \(2x \leq b\),那么直接购买 \(2x\) 更优;

若 \(2x > b\),那么就可以考虑将之前的决策反悔。

对于反悔操作,可以发现实际上减少的代价为 \(2x-b\)。那么就可以直接把这个 \(2x-b\) 看成一个免费的物品丢到小根堆中。表示此时又可以反悔操作 \(2\)。而 \(2x-b\) 反悔后,自然又可以反悔一次买 \(a\) 免费 \(b\) 的操作。而由于 \(x<b\),自然有 \(2x-b<b\),那么在小根堆里自然先会反悔 \(2x-b\) 再反悔 \(b\)。直接把 \(b\) 也丢入小根堆中即可。

如果当前枚举到的 \(x\) 的价值大于堆顶元素,那么显然反悔堆顶的决策,转而免费这两个(如果只剩下一个 \(x\) 就只免费这一个)物品会更优,直接将两个 \(x\) 丢入堆中即可。

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5e5+10;
#define LL long long
priority_queue<int,vector<int>,greater<int> >q;
int a[N],b[N],n,m,cnt[N],num[N];
LL ans;
int main()
{
	scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]),ans+=a[i];
	sort(a+1,a+n+1);reverse(a+1,a+n+1);
	for(int i=1;i<=n;i++)
	{
		if(i==1||a[i]!=a[i-1]) num[++m]=a[i];
		cnt[m]++;
	}
	int c1=0,c2=0,p=0;
	for(int i=1;i<=m;i++)
	{
		p=min(c1-2*(int)q.size(),cnt[i]);c2=0;
		for(int j=1;j<=p;j++) b[++c2]=num[i];
		p=min(c1,cnt[i])-p;//p为当前最多可以免费的数量 
		for(int j=1;j<=p;j+=2)
		{
			int x=q.top();
			if(x<num[i])
			{
				b[++c2]=num[i];
				if(j<p) b[++c2]=num[i];
			}
			else
			{
				b[++c2]=x;//b
				int y=2*num[i]-x;
				if(j<p&&y>0) b[++c2]=y;//2x-b>0
			}
			q.pop();
		}
		for(int j=1;j<=c2;j++) q.push(b[j]);
		c1+=cnt[i];
	}
	while(!q.empty()) ans-=q.top(),q.pop();
    printf("%lld\n",ans);
 	return 0;
}

标签:Buy,Get,int,CF335F,2x,反悔,物品,include,免费
来源: https://www.cnblogs.com/NLCAKIOI/p/16506759.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有