2020kickstart E round C Toys (优先队列)

题意:

有n个toy排成一个圈圈,每个toy有一个e[i],r[i],需要e[i]的时间去玩这个toy,r[i]可以理解为这个玩具再次可以被玩的cd时间,一个小孩会从第0个玩具开始,每次往i+1个玩具轮流玩过去,一个玩具可以被玩的前提是,距离上次被玩的时间超过r[i],当碰到不能玩的玩具后,小孩就会停下不动,否则一直玩下去。问移除多少个toy,可以让小孩玩的时间最长,并且再保证时间最长的情况下,移除最少的玩具。

 

思路:

第一轮肯定是都可以玩耍,关键是看第二轮,我们记完成一轮玩具的时间为tim,那么判断一个玩具再第二轮的时候是否可以玩就是判单tim-e[i]>=r[i],如果大于等于就是可以玩,小于就是不行。

然后这个问题最简单的思路其实就是第二轮的时候我们碰到不能玩的就移除,依次移除,但是有个问题,移除之后tim再变小,又会有更多的toy不能被玩,就需要第三轮删除,第四轮删除。这样就会变成一个n^2的算法,肯定不行。

然后值得注意的是,toy被删除的顺序其实不重要,因为r[i]>tim-e[i]就必须每个都要删除,所以我们删除的时候没必要按照玩的顺序去删除,而是直接找出满足t[i]>tim-e[i]的toy删除就行,不用管顺序。然后这时候我们就是要找当tim变化时,哪些toy变成满足r[i]>tim-e[i]了。但是这样很难直接找,就可以考虑转换一下不等式,变成找r[i]+e[i]>sum的出来删除,这样就很容易维护一个r[i]+e[i]的优先队列,我们只需要按顺序遍历toy,然后删除toy更新tim的时候,去优先队列里看top()的值是否大于新的tim就行,这样最多删除n次,时间复杂度就是o(nlogn)了,最后如果没有都被删除,就是可以无限时间玩下去。

 

代码:

#include <bits/stdc++.h>
#define ps push_back
using namespace std;
const long long inf=1e18;
const int maxn=1e5+5;
int n;
int e[maxn], r[maxn];
long long ans;
int num;
struct node
{
    int x;
    int id;
    bool operator <(const node& a)const{
        return x<a.x;
    }
};
void solve()
{
    cin>>n;
    ans=0;
    priority_queue<node>q;
    for(int i=0; i<n; i++)
    {
        scanf("%d%d", &e[i], &r[i]);
    }
    if(n==1)
    {
        printf("0 %d\n", e[0]);
        return;
    }
//    dfs(0);
    long long tim=0;
    for(int i=0; i<n; i++)
    {
        tim+=e[i];
    }
    long long max_tim=tim, cur_tim=tim;

    num=0;
    int cnt=0;
    for(int i=0; i<n; i++)
    {
        node tmp;
        tmp.x=e[i]+r[i];
        tmp.id=i;

        if(tmp.x>tim)
        {
            tim-=e[i];
            cur_tim-=e[i];
            cnt++;
            while(!q.empty() && q.top().x>tim)
            {
                tmp=q.top();
                tim-=e[tmp.id];
                cur_tim-=2*e[tmp.id];
                q.pop();
                cnt++;
            }
        }
        else {
            q.push(tmp);
            cur_tim+=e[i];
        }
        if(cur_tim>max_tim)
        {
            num=cnt;
            max_tim=cur_tim;
        }
    }
    if(cnt!=n)
    {
        num=cnt;
        max_tim=inf;
    }
    if(max_tim!=inf)printf("%d %lld\n", num, max_tim);
    else printf("%d INDEFINITELY\n", num);
}
int main()
{
//    ios::sync_with_stdio(0);
//    cin.tie(0);
    int t;
    cin>>t;
    for(int i=1; i<=t; i++){
        cout<<"Case #"<<i<<": ";
        solve();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值