Codeforces 1154E

本文探讨了一种竞赛编程中的团队分配问题,通过链表实现的高效算法,能够在O(nlogn)的时间复杂度内解决n个人的能力值排列问题。具体介绍了如何使用链表维护人员及其能力值,以及如何通过定位最大值快速完成团队分配。

有n个人,每个人的能力值是1到n的排列;
两队轮流取人,每次取出当前能力值最大的人,以及他左边k个人和右边k个人(不足k个则全部取走);
请问最后每个人在哪个队伍中。

这题严格的做法应该是可以做到O(n)O(n)O(n)的,不过并没有卡O(nlogn)O(nlogn)O(nlogn)
考虑每次找最大值,因为每次取出的数都是连续的,所以用链表实现,修改头尾指针即可。
注意每次找最大值的时候可以用f[i]f[i]f[i]记录i出现的位置,直接定位即可。

#include<iostream>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define N 300000
using namespace std;
int n,k,i,j,r,st,ed;
int f[N],a[N],pre[N],suc[N],res[N];
int main()
{
    cin>>n>>k;
    fo(i,1,n)
    {
        cin>>a[i];
        f[a[i]] = i;
        pre[i] = i - 1;
        suc[i] = i + 1; //记录位置、前驱、后继
    }
    r = 1;
    fd(i,n,1)
    if (f[i])//寻找当前的最大值
    {
        ed = f[i];
        fo(j,1,k)//向后找
        {
            if (suc[ed] == n + 1) break;
            ed = suc[ed];
            f[a[ed]] = 0; res[ed] = r;
        }
        ed = suc[ed];
        
        st = f[i];
        fo(j,1,k)//向前找
        {
            if (pre[st] == 0) break;
            st = pre[st];
            f[a[st]] = 0; res[st] = r;
        }
        st = pre[st];
        
        suc[st] = ed; pre[ed] = st;//删除
        res[f[i]] = r; f[i] = 0;
        r = 3 - r;
    }
    fo(i,1,n) cout<<res[i]; cout<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值