题目:
如果一个序列的任意连续的子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的。输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是不是不无聊的。
思路:
分治法,平常确实用的非常的少,这次借这个题目熟悉一下。代码思路是学习的紫书上的代码的。
在[L,R]范围内枚举是唯一的数,从这个数的左右两边开始判断是不是左右两边的序列都符合唯一性条件。(包含这个唯一数的区间都是符合条件的,所以只要在从两边开始枚举就可以了。)
代码:
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1e3 #define FRE() freopen("in.txt","r",stdin) #define FRO() freopen("out.txt","w",stdout) using namespace std; typedef long long ll; const int maxn = 200005; int pre[maxn],nxt[maxn],a[maxn]; map<int,int> mp; int n; bool isUnion(int pos,int L, int R){//检查在L、R的范围内pos上的数是不是唯一的 return pre[pos]<L && nxt[pos]>R; } bool check(int L,int R){ if(L>=R) return true;//如果能达到中点,表示都符合条件 for(int i=0; L+i <= R-i; i++){//枚举L、R之间所有的点,看这个点的两边是不是都符合条件 if(isUnion(L+i,L,R)) return check(L,L+i-1)&&check(L+i+1,R);//从左边开始枚举 if(i+L==R-i) break; if(isUnion(R-i,L,R)) return check(L,R-i-1)&&check(R-i+1,R);//从右边开始枚举 } return false; } int main(){ //FRE(); int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0; i<n; i++){ scanf("%d",&a[i]); } mp.clear(); for(int i=0; i<n; i++){//pre[i]表示位置i上的数左边与之相同的数的位置 if(!mp.count(a[i])){ pre[i] = -1; }else{ pre[i] = mp[a[i]]; } mp[a[i]] = i; } mp.clear(); for(int i=n-1; i>=0; i--){//nxt[i]表示位置i上的数右边与之相同的数的位置 if(!mp.count(a[i])){ nxt[i] = n; }else{ nxt[i] = mp[a[i]]; } mp[a[i]] = i; } if(check(0,n-1)){ printf("non-boring\n"); }else{ printf("boring\n"); } } return 0; }