传送门biu~
我们可以把相同的数字用双向链表串起来,pre[x]为x位置之前第一个和x位置数字相同的位置,
nexx
n
e
x
x
为
x
x
位置之后第一个和位置数字相同的位置。对于区间
[l,r]
[
l
,
r
]
,当存在位置
x
x
使且
nexx>r
n
e
x
x
>
r
。则这个区间是不无聊的,而且区间
[l,r]
[
l
,
r
]
的所有包含
x
x
位置的子区间也是不无聊的,所以可以递归判断区间和
[x+1,r]
[
x
+
1
,
r
]
。
对于区间
[l,r]
[
l
,
r
]
,如果按
l
l
~的顺序枚举满足
prex<l
p
r
e
x
<
l
且
nexx>r
n
e
x
x
>
r
的位置
x
x
,那么最坏的情况下,位置在位置
r
r
处。这样就会向下递归层。时间复杂度
O(n2)
O
(
n
2
)
。
而如果对于区间
[l,r]
[
l
,
r
]
,从两边向中间枚举,那么最坏的情况下,位置
x
x
在位置处,
这样会向下递归
logn
log
n
层,时间复杂度
O(nlogn)
O
(
n
log
n
)
。这就是启发式分裂的思想。
那么再加个map应该是
O(nlog2n)
O
(
n
log
2
n
)
。(划掉)
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200005];
map<int,int>head,nex,pre;
bool check(int L,int R){
if(L>R) return true;
int x=L-1,y=R+1;
while(++x<=--y){
if(pre[x]<L && nex[x]>R) return (check(L,x-1) && check(x+1,R));
if(pre[y]<L && nex[y]>R) return (check(L,y-1) && check(y+1,R));
}
return false;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
head.clear();
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
pre[i]=head[a[i]];
nex[i]=n+1;
nex[head[a[i]]]=i;
head[a[i]]=i;
}
printf(check(1,n)?"non-boring\n":"boring\n");
}
return 0;
}