传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4059
【题解】
考虑分治。定义过程solve(l,r)为判断全在[l,r]范围内的所有连续子序列是不是non-boring的
那么我们预处理每个地方的前一个与它相同的数pre[i]和后一个与它相同的数nxt[i]。
显然对于i属于[l,r],如果存在pre[i]<l,nxt[i]>r,那么任何经过i的连续子序列都合法,所以就分成[l,i-1]和[i+1,r]检测即可。
为了保证复杂度,我们要从两边同时往中间搜,这样复杂度为
T(n) = max{T(n-k) + T(k) + O(min(k, n-k))} = O(nlogn)
或者用“启发式合并”的逆过程也能证明。
# include <stdio.h> # include <algorithm> # include <vector> // # include <bits/stdc++.h> using namespace std; int T, n, a[200010], pre[200010], nxt[200010]; int lst[200010], na[200010]; vector<int> vec; vector<int>::iterator it; inline bool judge(int l, int r) { if (l == r) return 1; if (l == r-1) return a[l] != a[r]; for (int i=l, j=r; i<=j; ++i, --j) { if(pre[i] < l && nxt[i] > r) { if(i != l) return judge(l, i-1) && judge(i+1, r); else return judge(i+1, r); } if(pre[j] < l && nxt[j] > r) { if(j != r) return judge(l, j-1) && judge(j+1, r); else return judge(l, j-1); } } return 0; } inline void out(int *ot, int ed) { for (int i=1; i<=ed; ++i) printf("%d ", ot[i]); puts(""); } int main() { scanf("%d", &T); while(T--) { vec.clear(); scanf("%d", &n); for (int i=1; i<=n; ++i) { scanf("%d", &a[i]); pre[i] = 0, nxt[i] = n+1; vec.push_back(a[i]); } sort(vec.begin(), vec.end()); it = unique(vec.begin(), vec.end()); vec.erase(it, vec.end()); for (int i=1; i<=n; ++i) na[i] = lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin() + 1; for (int i=1; i<=n; ++i) lst[i] = 0; for (int i=1; i<=n; ++i) { if(lst[na[i]] != 0) pre[i]=lst[na[i]]; lst[na[i]]=i; } for (int i=1; i<=n; ++i) lst[i] = n+1; for (int i=n; i>=1; --i) { if(lst[na[i]] != n+1) nxt[i]=lst[na[i]]; lst[na[i]]=i; } //out(pre, n); //out(nxt, n); if(judge(1, n)) puts("non-boring"); else puts("boring"); } return 0; }