Toys KickStart2020E轮

https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ff47/00000000003bede9#problem

首先考虑无限的情况,设sum为e[i]之和,那么当所有的玩具都满足sum-e[i]>=r[i]时,就可以无限

那么我们先假设存在无限的情况,思考如何找出最小删除多少个物品

可以发现条件是sum>=e[i]+r[i],那么对于最大的e[i]+r[i]如果他不满足,则必须把他删掉,为什么不删其他非法的呢,因为就算删掉别的,只是sum减小,而e[i]+r[i]是不变的,他还是得删掉,所以我们优先删最大的,删到不能删为止,如果此时没有删光,那么就是无限的。

然后我们考虑最后删光的情况,求出最大值

首先考虑第一轮肯定是可以全玩的,因为还没有玩过,所以sum=e[1]+...e[n],问题出在第二轮,我们设第2轮的时间为cur,按照顺序依次考虑是否进入,如果e[i]+r[i]<=sum,说明可以进入,那么q.push(a[i]),cur+=e[i],否则说明第i个玩具必须被丢掉,因为我们的sum是假设只处理了前i个玩具,后面的玩具都是在队列里的,说明sum是随着处理递减的,那么e[i]+r[i]>sum以后也无法改变,所以必须被丢掉。然而此时我们导致了sum减小,所以一些前面已经加入队列的可能也要丢掉,while循环丢一下,丢完以后就判断一下sum+cur是否大于已知最优答案就行了。

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

const int maxl=3e5+10;

int n,m,cas,k,cnt,tot,ans;ll ansmx;
int e[maxl],r[maxl];
struct node
{
	int val,id;
	bool operator < (const node &b)const
	{
		if(val==b.val)
			return id<b.id;
		return val<b.val;
	}
}a[maxl];
priority_queue<node> q;
char s[maxl];
bool in[maxl]; 

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&e[i],&r[i]);
		a[i]=node{e[i]+r[i],i};
	}
} 

inline void mainwork()
{
	ll sum=0,cur;int del;
	while(!q.empty())
		q.pop();
	for(int i=1;i<=n;i++)
		sum+=e[i],q.push(a[i]);
	while(!q.empty())
	{
		if(q.top().val<=sum)
			break;
		else
			sum-=e[q.top().id],q.pop();
	}
	if(!q.empty())
	{
		ans=n-q.size();ansmx=-1;
		return;
	}
	while(!q.empty())
		q.pop();
	del=0;sum=0;node d;
	for(int i=1;i<=n;i++)
		sum+=e[i],in[i]=true;
	cur=0;ansmx=sum;ans=0;
	for(int i=1;i<=n;i++)
	if(in[i])
	{
		if(e[i]+r[i]<=sum)
		{
			cur+=e[i];
			q.push(a[i]);
		}
		else
		{
			del++;sum-=e[i];
			while(!q.empty())
			{
				if(q.top().val<=sum)
					break;
				else
				{
					d=q.top();q.pop();
					sum-=e[d.id];
					cur-=e[d.id];
					++del;
				}
			}	
		}
		if(sum+cur>ansmx)
			ansmx=sum+cur,ans=del;
	}
}

inline void print()
{
	printf("Case #%d: ",cas);
	if(ansmx<0)
		printf("%d INDEFINITELY\n",ans);
	else	
		printf("%d %lld\n",ans,ansmx);
}

int main()
{
	int t=1;
	scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108191990
今日推荐