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