题目链接 : http://codeforces.com/contest/1154/problem/E
题意 :
给你n个值(1~n且不重复),选中最大的数,并将它左边k个元素和右边k个元素(可能不足,不足的部分不考虑)选中标记为 1 ,这2*k+1个元素同时从数组中删除。重复操作,但是标记为2,结束一轮。
重复任意多轮,直至所有数都被标记(1 or 2)。
当时并没有好的思路,赛后看的别人的代码才会的。
大佬的AK日常: https://www.jianshu.com/p/fd764cf686e9
考虑到数据是1~n的全排列, 所以我们可以用数组来将元素的位置离散出来。
实现类似于双链表的数据结构,用于快速找到当前元素的左右相邻元素。

#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn = 2e5+5; int n, k; int sk[maxn], le[maxn], ri[maxn]; int arr[maxn], ans[maxn]; void remo(int ind){ le[ri[ind]] = le[ind]; ri[le[ind]] = ri[ind]; } int main(){ memset(ans,0,sizeof(ans)); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&arr[i]); sk[arr[i]] = i; le[i] = i-1; ri[i] = i+1; } ans[0] = ans[n+1] = -1;// 边界 int team = 1; for(int i=n;i>=0;i--){ int index = sk[i]; if(ans[index]) continue; remo(index); ans[index] = team; int l = le[index], r = ri[index]; for(int i=0;i<k;i++,l=le[l]){ if(ans[l]) break; remo(l); ans[l] = team; } for(int i=0;i<k;i++,r=ri[r]){ if(ans[r]) break; remo(r); ans[r] = team; } team = 3 - team; } for(int i=1;i<=n;i++) printf("%d",ans[i]); putchar(' '); return 0; }