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;
}