1. 程式人生 > >UVA - 1608 Non-boring sequences(分治法)

UVA - 1608 Non-boring sequences(分治法)

name 表示 urn its mes else pac 學習 tro

題目:

如果一個序列的任意連續的子序列中至少有一個只出現一次的元素,則稱這個序列是不無聊的。輸入一個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; }

UVA - 1608 Non-boring sequences(分治法)