codeforces1398E Two Types of Spells

本文详细解析了Codeforces竞赛1398题E的算法思路,通过维护三个集合实现最优解,探讨了如何在比赛中高效解决问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://codeforces.com/contest/1398/problem/E

设当前有cnt个光之符卡

维护3个set,c表示最大的cnt个符卡,f1表示不是c中的剩下的火卡,l1表示不是c中的剩下的光卡

那么答案就是c中的所有卡的值*2+剩下的卡的值,sum为所有卡的值,sum1位c中卡的值,ans=sum+sum1

接下来我们就只需要维护c中总是所有卡中最大的cnt个就行了,当前szc!=cnt都判断一下,然后如果剩下的卡中有比c最小的卡大的就替换一下

注意特判特殊情况,维护一个cntc,表示c中有多少个光之符卡,如果cntc==cnt的话,也就是c中全是光之符卡,那必有一个无法*2,把最小的去掉然后加上剩下的火卡中最大的就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=2e5+10;

int n,cnt;ll ans,sum,sum1;
struct spell
{
	int val,tp,id;
	bool operator < (const spell &b)const
	{
		if(val==b.val)
		{
			if(tp==b.tp)
				return id<b.id;
			return tp<b.tp;
		}
		return val<b.val;
	}
	bool operator == (const spell &b)const
	{
		return id==b.id;
	}
	bool operator > (const spell &b)const
	{
		if(val==b.val)
		{
			if(tp==b.tp)
				return id>b.id;
			return tp>b.tp;
		}
		return val>b.val;
	}
}a[maxl];
set<spell> f1,l1,c;
set<spell> :: iterator it; 

inline void prework()
{
	scanf("%d",&n);
}

inline void mainwork()
{
	sum=0;ans=0;sum1=0;cnt=0;
	int szc=0,cntc=0,fmx,lmx;
	spell d;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].tp,&a[i].val);
		a[i].id=i;
		if(a[i].val>0)
		{
			sum+=a[i].val;
			if(a[i].tp==0)
				f1.insert(a[i]);
			else
			{
				l1.insert(a[i]);
				++cnt;
			}
		}
		else
		{
			if(a[i].tp==0)
			{
				sum+=a[i].val;
				it=c.lower_bound({-a[i].val,0,0});
				if(it!=c.end() && (*it).val==-a[i].val && (*it).tp==0)
					sum1+=a[i].val,c.erase(it),szc--;
				else
					f1.erase(f1.lower_bound({-a[i].val,0,0}));
			}
			else
			{
				--cnt;sum+=a[i].val;
				it=c.lower_bound({-a[i].val,1,0});
				if(it!=c.end() && (*it).val==-a[i].val && (*it).tp==1)
					sum1+=a[i].val,c.erase(it),szc--,cntc--;
				else
					l1.erase(l1.lower_bound({-a[i].val,1,0}));
			}
		}
		while(szc<cnt)
		{
			if(f1.begin()==f1.end())
			{
				it=l1.end();--it;c.insert(*it);
				sum1+=(*it).val;szc++;cntc++;		
				l1.erase(it);
			}
			else if(l1.begin()==l1.end())
			{
				it=f1.end();--it;c.insert(*it);
				sum1+=(*it).val;szc++;
				f1.erase(it);
			}
			else
			{
				if((*f1.rbegin()).val>=(*l1.rbegin()).val)
				{
					it=f1.end();--it;c.insert(*it);
					sum1+=(*it).val;szc++;
					f1.erase(it);
				}
				else
				{
					it=l1.end();--it;c.insert(*it);
					sum1+=(*it).val;szc++;cntc++;		
					l1.erase(it);
				}
			}
		}
		while(szc>cnt)
		{
			d=(*c.begin());sum1-=d.val;
			if(d.tp==0) 
				f1.insert(d);
			else 
				l1.insert(d),--cntc;
			szc--;c.erase(c.begin());
		}
		while(cnt>0)
		{
			fmx=0;lmx=0;
			if(f1.begin()!=f1.end())
				fmx=(*f1.rbegin()).val;
			if(l1.begin()!=l1.end())
				lmx=(*l1.rbegin()).val;
			d=*c.begin();
			if(max(fmx,lmx)<=d.val)
				break;
			sum1-=d.val;c.erase(c.begin());
			if(d.tp==1) cntc--;
			if(fmx>lmx)
			{
				sum1+=fmx;it=f1.end();--it;
				c.insert(*it);f1.erase(it);
			}
			else
			{
				sum1+=lmx;it=l1.end();--it;++cntc;
				c.insert(*it);l1.erase(it);
			}
			if(d.tp==0)
				f1.insert(d);
			else
				l1.insert(d);
		}
		if(cnt>0 && cnt==cntc)
		{
			ans=sum1+sum-(*c.begin()).val;
			if(f1.begin()!=f1.end())
				ans+=(*f1.rbegin()).val;
		}
		else
			ans=sum1+sum;
		printf("%lld\n",ans);
	}
}

int main()
{
	prework();
	mainwork();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值