Description
我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短。一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子序列里至少存在一个数字只出现一次。给定一个整数序列,请你判断它是不是不无聊的。
Input
第一行一个正整数T,表示有T组数据。每组数据第一行一个正整数n,表示序列的长度,1 <= n <= 200000。接下来一行n个不超过10^9的非负整数,表示这个序列。
Output
对于每组数据输出一行,输出"non-boring"表示这个序列不无聊,输出"boring"表示这个序列无聊。
Sample Input
4
5
1 2 3 4 5
5
1 1 1 1 1
5
1 2 3 2 1
5
1 1 2 1 1
5
1 2 3 4 5
5
1 1 1 1 1
5
1 2 3 2 1
5
1 1 2 1 1
Sample Output
non-boring
boring
non-boring
boring
boring
non-boring
boring
题解:
预处理出每个数的前一个位置和后一个位置.
对于一个数x它的位置是i,当l在[pre[i],i-1],r在[i+1,next[i]]之间时,[l,r]中x只出现过一次.
我们把每个x能产生贡献的区间放到二维平面上,显然是一个矩阵.
然后我们就可以扫描线+线段树处理.
这样会很慢.
正解是暴力.复杂度的证明非常神奇.
可以看这里:http://whx991201.is-programmer.com/posts/190036.html
代码:
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 210000
using namespace std;
map<int,int>point;
int pre[N],next[N],T,n,x,a[N];
bool check(int l,int r){
int h=l,t=r;
if (l>=r) return 1;
for (int i=l;i<=r;i++)
if (i&1){
if (pre[h]<l&&next[h]>r) return check(l,h-1)&&check(h+1,r);
h++;
}
else{
if (pre[t]<l&&next[t]>r) return check(l,t-1)&&check(t+1,r);
t--;
}
return 0;
}
int main(){
scanf("%d",&T);
while (T--){
point.clear();
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&x);
next[point[x]]=i;
pre[i]=point[x];
point[x]=i;a[i]=x;
}
for (int i=1;i<=n;i++) next[point[a[i]]]=n+1;
if (check(1,n)) puts("non-boring");
else puts("boring");
}
}