解题思路
考虑分治。虽然我觉得就是暴力
对于一个数,左边第一个与它一样的数的位置记为z[i],右边第一个记为y[i]。
对于区间[l,r],如果其中存在一个数i,使z[i] < l 并且 y[i] > r,那么区间[l,r]是一定符合题目中条件的,只要这个区间的子区间[l,i-1]和[i+1,r]也符合条件,区间[l,r]就是不无聊的。于是这么分治下去就行了。
但是这么写会T,确切的说会被卡成
O
(
在区间[l,r]中枚举 i 的时候,从两边向中间找,这样枚举下来就成了
O
(
上午发的这篇博客,但是并不清楚复杂度是怎么证的,然而下午就被zP1nG大佬证出来了%%%
如果每次从左向右枚举,就可能每层要找的i都在最左边或最右边,这样每层都要枚举n次,而且要跑n层递归,这样就会变成
n2
。
但是如果每次从两边向中间枚举,就不会扫遍整个序列。最坏的情况是i在序列中间,这时候就会在每一层跑满n次,但因为每次序列长度都除以2,所以最多log层,合起来就是最坏
O
(
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
int sh[200005],xi[200005];
int hed[200005];
int s[200005],b[200005];
int n,T;
bool check(int x,int y){
if(x>y) return 1;
int lx=x,ly=y;
while(lx<=ly){
if(sh[lx]<x && xi[lx]>y)
return check(x,lx-1) && check(lx+1,y);
lx++;
if(sh[ly]<x && xi[ly]>y)
return check(x,ly-1) && check(ly+1,y);
ly--;
}
return 0;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
b[i]=s[i];hed[i]=0;
}
sort(b+1,b+n+1);
int top=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) s[i]=lower_bound(b+1,b+top+1,s[i])-b;
for(int i=1;i<=n;i++){
sh[i]=hed[s[i]];
hed[s[i]]=i;
}
for(int i=1;i<=n;i++) hed[i]=n+1;
for(int i=n;i>=1;i--){
xi[i]=hed[s[i]];
hed[s[i]]=i;
}
if(check(1,n)) printf("non-boring\n");
else printf("boring\n");
}
return 0;
}