题意:如果一个序列的任意连续子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的.输入一个n(n <= 200000)个元素的序列A,判断它是不是无聊的.
分析:对一段序列[l,r]而言,我们先找到这整个序列中只出现了一次的元素,如果没有那么就可以直接返回false,假如我们得到了这个元素p,那么接下来只需要递归的去检查区间[l,p-1]和
[p+1,r]就行了,我们事先预处理出来每个元素前后最近相同元素的位置就可以o(1)的判断这个数字是不是在某个子序列中只出现了一次,这样我们可以扫一遍[l,r]来得到p.
设T(n)为规模为n时所需的时间,那么T(n) = max(T(p-1) + T(n-p) + O(n)),最坏情况下T(n) = O(n^2).但是如果我们从两边开始同步找p,复杂度就变成了T(n) = max(T(p-1)+T(n-p)+min(p,n-p)),最坏情况下每次p都在[l,r]中点,此时T(n) = 2*T(n/2) + O(n) = O(n*log(n)).
#include <bits/stdc++.h>
#define N 200005
using namespace std;
int T,n,a[N],pre[N],suc[N];
unordered_map<int,int> f;
bool jud(int l,int r)
{
if(l >= r) return true;
int flag = 0;
int x = l,y = r;
while(x <= y)
{
if(pre[x] < l && (!suc[x] || suc[x] > r))
{
flag = x;
break;
}
if(pre[y] < l && (!suc[y] || suc[y] > r))
{
flag = y;
break;
}
x++,y--;
}
if(!flag) return false;
return jud(l,flag-1)&&jud(flag+1,r);
}
int main()
{
scanf("%d",&T);
while(T--)
{
f.clear();
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
for(int i = 1;i <= n;i++)
{
pre[i] = f[a[i]];
f[a[i]] = i;
}
f.clear();
for(int i = n;i;i--)
{
suc[i] = f[a[i]];
f[a[i]] = i;
}
cout<<(jud(1,n) ? "non-boring" : "boring")<<endl;
}
}