UVa 1608

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4483

题意:

如果一个序列的任意连续子序列中至少有一个只出现一次的元素,则称这个序列是不无聊(non-boring)的。
输入一个n(n≤200000)个元素的序列A(各个元素均为1e9以内的非负整数),判断它是不是不无聊的。

分析:

在整个序列中找一个只出现一次的元素,如果不存在,则这个序列不是不无聊的;
如果找到一个只出现一次的元素A[k],则只需检查A[1…k-1]和A[k+1…n]是否满足条件(分治)。
设长度为n的序列需要T(n)时间,则有T(n) = max{T(k-1) + T(n-k) + 找到唯一元素k的时间}。
如何找唯一元素?如果事先算出每个元素左边和右边最近的相同元素,
则可以在O(1)时间内判断在任意一个连续子序列中,某个元素是否唯一。
如果从左边找,最坏情况下唯一元素是最后一个元素,因此
T(n) = T(n-1) + O(n)≥T(n) = O(n*n)
从右往左找也一样,只不过最坏情况变成了“唯一元素是第一个元素”,但时间复杂度不变。
那么,从两边往中间找会怎样?此时T(n) = max{T(k) + T(n-k) + min(k,n-k)},
而此时的最坏情况是唯一元素在中间的情况,它满足经典递推式T(n) = 2T(n/2) + O(n),即T(n)=O(nlogn)。

代码:

 1 #include <cstdio>
 2 #include <map>
 3 using namespace std;
 4 
 5 const int UP = 200000 + 5;
 6 int a[UP], prior[UP], after[UP];
 7 
 8 inline bool check(int p, int L, int R){
 9     return prior[p] < L && after[p] > R;
10 }
11 
12 bool judge(int L, int R){
13     if(L >= R) return true;
14     for(int d = 0; L + d <= R - d; d++){
15         if(check(L+d, L, R)) return judge(L, L+d-1) && judge(L+d+1, R);
16         if(L + d == R - d) break;
17         if(check(R-d, L, R)) return judge(R-d+1, R) && judge(L, R-d-1);
18     }
19     return false;
20 }
21 
22 int main(){
23     int T, n;
24     scanf("%d", &T);
25     while(T--){
26         map<int,int> M;
27         scanf("%d", &n);
28         for(int i = 0; i < n; i++){
29             scanf("%d", &a[i]);
30             prior[i] = M.count(a[i]) ? M[a[i]] : -1;
31             M[a[i]] = i;
32         }
33         M.clear();
34         for(int i = n - 1; i >= 0; i--){
35             after[i] = M.count(a[i]) ? M[a[i]] : n;
36             M[a[i]] = i;
37         }
38 
39         if(judge(0, n-1)) printf("non-boring
");
40         else printf("boring
");
41     }
42     return 0;
43 }
原文地址:https://www.cnblogs.com/hkxy125/p/8310924.html