[CF335F]Buy One, Get One Free

Keywords: Algorithm

Buy One, Get One Free

Problem solution

First of all, if it has no requirements and can only choose strictly less than as a gift, I think it should be easy for us to think of a greedy strategy of choosing one after the other.
But obviously, under the strict requirements, we can't do so and consider going back on our greed.
We can reduce gifts with the same price into one category and deal with them one by one. Obviously, gifts in the same category cannot be established B u y − G e t Buy-Get Buy − Get relationship.
If we had B u y Buy Buy's gift ratio G e t Get Get has a lot of gifts. It's obvious that we can go directly now G e t Get Get gift.
If we can't now G e t Get Get, at this time, we have to consider whether to buy these gifts or the front G e t Get Buy some gifts from Get and go again G e t Get Get these gifts.
This can obviously be solved by turning back on greed.
It is obvious that one time of repentance will increase 2 2 2 places for G e t Get Get the number of gifts, that is, the number of gifts we are currently processing + 2 +2 +2, and B u y Buy Buy gift will also bring us one G e t Get Get quota so that we can handle the number of gifts + 2 +2 +2.
If our current minimum cost of reneging x ⩽ 2 v a l i x\leqslant 2val_{i} x ⩽ 2vali is equivalent to the treatment after we renege. The cost of these two same gifts is lower. We renege and add these two to the answer. Obviously, the cost of these two reneges is 2 v a l i − x 2val_{i}-x 2vali − x, and if we go back on the previous one, we can also go back on it again x x x. So we're going to add both to the heap.
The price of our repudiation is to find the smallest one at a time, which can be maintained through the smallest heap.

However, the above estoppel is when we have two identical values, but we may encounter a situation where the current value is only one number. In this case, if our x ⩽ v a l i x\leqslant val_{i} x ⩽ vali, we can also go back through repentance G e t Get Get the next one, which will add one to us G e t Get Get the quota, which is still the optimal method.
So we have to deal with the above two cases.
Just the estoppel cost of the priority queue maintenance.

Time complexity O ( n log ⁡   n ) O\left(n\log\,n\right) O(nlogn).

Source code

#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;       
const int INF=0x3f3f3f3f;       
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,a[MAXN],b[MAXN],cnt[MAXN],tot,now,sta[MAXN],stak,sum;LL ans;
priority_queue<int,vector<int>,greater<int> >q;
signed main(){
	read(n);for(int i=1;i<=n;i++)read(a[i]),b[++tot]=a[i],ans+=a[i];
	sort(b+1,b+tot+1);tot=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+tot+1,a[i])-b,cnt[a[i]]++;
	for(int i=tot;i>0;i--){
		now=sum-2*q.size();sum+=cnt[i];
		while(now&&cnt[i])now--,cnt[i]--,sta[++stak]=b[i];
		while(!q.empty()&&cnt[i]>0)
			if(q.top()>=b[i]){
				if((cnt[i]^1)&&b[i]+b[i]>=q.top())
					sta[++stak]=b[i]+b[i]-q.top();
				sta[++stak]=q.top();
				q.pop();cnt[i]-=2;
			}
			else{
				sta[++stak]=b[i];
				if(cnt[i]^1)sta[++stak]=b[i];
				q.pop();cnt[i]-=2;
			}
		while(cnt[i]>0)cnt[i]--;
		while(stak)q.push(sta[stak--]);
	} 
	while(!q.empty())ans-=q.top(),q.pop(); 
	printf("%lld\n",ans);
	return 0;
}

thank you!!!

Posted by horstuff on Sat, 20 Nov 2021 17:06:32 -0800