Codeforces Round #552 (Div3)E

Codeforces Round #552 (Div. 3) E Two Teams

题意:

​ n个人排成一排,每个人都有一个iq,且iq不重复。现在给你一个k,且有两个教练编号为分别为1,2轮流进行以下操作

​ 该教练从排成的一行中找出iq最大的人加入自己的团队,且让iq最大的人左边的k个人和右边的k个人都加入自己的团队(如果人数不够k个,则只把剩余的加入即可)。

​ 现在问所有的人都被选出之后所处的团队编号。

思路:

​ 我们需要维护两个信息

  1. 一行人的编号的顺序,以及对应的iq.
  2. 此时所有人的iq最大的人的编号。

​ 我们第一个可以采用set容器实现;第二个使用map容器实现(也可以采用线段树维护),即让一个iq对应一个编号。

​ 那么每次删除中只要找到最大的iq对应的编号,然后在set容器中删除他左边和右边的信息,同时在map中删除对应的记录即可。
每次删除和查找的时间复杂度为logn,总体时间复杂度为nlogn
代码:

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll MAXN=2e5+20;
const int MAX=100000;
const int inf=0x3f3f3f3f;
set<int> seq;
map<int,int> maxIQ;//val id
int n,k;
int ansb[MAXN],iq[MAXN];
int delleft(int id,int sign)
{
    int tot=0;
    set<int>::iterator it=seq.find(id);
    if(it==seq.begin())
        return tot;
    it--;
    while(tot<k)
    {
        tot++;
        if(it==seq.begin())
        {
            int id=*it;
            ansb[id]=sign;
            seq.erase(it--);
            maxIQ.erase(iq[id]);
            return tot;
        }
        else{
            int id=*it;
            ansb[id]=sign;
            seq.erase(it--);
            maxIQ.erase(iq[id]);
        }
    }
    return tot;
}
int delright(int id,int sign)
{

    int tot=0;
    set<int>::iterator it=seq.find(id);
    it++;
    while(it!=seq.end()&&tot<k)
    {
        int nowid=*it;
        int nowiq=iq[nowid];
        ansb[nowid]=sign;
        seq.erase(it++);
        maxIQ.erase(nowiq);
        tot++;;
    }
    return tot;
}
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1; i<=n; ++i)
    {
        scanf("%d",iq+i);
        seq.insert(i);
        maxIQ[iq[i]]=i;
    }
    int sign=0;
    mset(ansb,-1);
    int tot=n;
    while(tot)
    {
        int maxid=(maxIQ.rbegin()->second);
        int maxiq=maxIQ.rbegin()->first;
        tot-=delleft(maxid,sign);
        tot-=delright(maxid,sign);
        ansb[maxid]=sign;
        seq.erase(maxid);
        maxIQ.erase(maxiq);
        tot--;
        sign^=1;
    }
    for(int i=1;i<=n;++i)
        printf("%d",ansb[i]+1);
    puts("");
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值