1. 程式人生 > >Uva1608 Non-boring sequences 【分治+中途相遇】【例題8-16】

Uva1608 Non-boring sequences 【分治+中途相遇】【例題8-16】

題意:給一個序列,如果此序列中的任意子序列中至少尋找一個唯一的值就說明此序列為不無聊序列,否則為無聊序列。注意,任意子序列即所有的子序列都滿足才行!

思路:依然是參考了紫書+程式碼庫!

(1)預處理:分別從左邊和右邊來一遍,從左邊掃,當沒有出現重複值時,當前位置都賦值為-1,如果出現重複值了,將上一個值的位置記錄到當前出現重複的位置上,這裡可以用一個map集合實現儲存每個值對應的位置。同理,從右往左再掃一遍,沒有出現重複值時賦值最大值n,出現重複值同上!

(2)分治遞迴:從序列的左邊和右邊同時開始,往中間相遇,每次尋找當前子序列的一個值進行判斷它是否是唯一值,根據上面的預處理陣列,判斷當前值的左陣列出現重複值是否在當前範圍內,右邊同理也是。然後如果存在唯一值就繼續從這個唯一值的位置分開左右部分,再將左右部分同時進行分治遞迴,直到左邊界大於右邊界時即所有的子序列都有唯一值了!

參考:紫書-例8-16-P + 紫書程式碼庫

程式碼:

#include <iostream>
#include <stdio.h>
#include <map>
using namespace std;
const int maxn = 200005;
int pre[maxn],nex[maxn],arr[maxn];
map<int,int>cur;
int n;
void init(){
    cur.clear();
    for(int i=0;i<n;i++){//預處理從左邊起出現重複值的前一個值的位置
        if(!cur.count(arr[i]))pre[i] = -1;//當前arr[i]還是唯一值,將此位置賦為-1
        else pre[i] = cur[arr[i]];//arr[i]出現重複值,當此值的前一個的位置賦給當前記錄位置陣列
        cur[arr[i]] = i;//記錄每個值的位置
    }
    cur.clear();
    for(int i=n-1;i>=0;i--){//預處理從右邊起出現重複值的前一個值的位置
        if(!cur.count(arr[i])) nex[i] = n;//同上,只不過賦值為最大n,因為一會兒判斷唯一性時需要
        else nex[i] = cur[arr[i]];//同上
        cur[arr[i]] = i;
    }
}
inline bool unique(int p,int L,int R){
    return pre[p] < L && nex[p] > R;//判斷當前值在當前範圍中的唯一性
}
bool check(int L,int R){
    if(L >= R) return true;//達到中間點,說明所有都成立了
    for(int i=0;i+L <= R-i;i++){
        if(unique(L+i,L,R)) return check(L,L+i-1) && check(L+i+1,R);//從左開始 當前值時唯一性後進行分治
        if(i+L == R-i) break;
        if(unique(R-i,L,R)) return check(L,R-i-1) && check(R-i+1,R);//從右開始
    }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d",&arr[i]);
        init();
        if(check(0,n-1)) printf("non-boring\n");
        else printf("boring\n");
    }
    return 0;
}