題解 UVA1608 【不無聊的序列 Non-boring sequences】

思路:

算法很顯然:c++

1、在區間\([l,r]\)找到一個只出現一次的元素P(若是不存在,那麼序列\(boring\)算法

2、遞歸處理區間\([l,p-1]\)和區間\([p+1,r]\)spa

其關鍵在於如何找到一個只出現一次的元素P。code

首先,咱們得知道如何判斷一個元素是否是隻出現一次。遞歸

咱們能夠用\(STL\)中的\(map\)記錄與當前元素值相同的上一個元素 or 下一個元素的位置,而後更新便可。it

由於\(map\)的全部操做都是\(O(log_n)\)的,因此預處理的時間複雜度爲\(O(nlog_n)\)ast

因此,咱們就能夠用\(O(1)\)的時間判斷出一個元素是否是隻出現一次了。class

若從左到右掃描整個序列,那麼最壞狀況,這個元素在序列的最右邊,則\(Time(n)=Time(n-1)+O(n) \ge Time(n^2)=O(n^2)\)map

根據二分法(分治)通常是儘可能分紅兩個數量儘可能接近的數列,咱們能夠考慮從兩邊往中間找。im

此時,最壞狀況爲這個元素在序列的正中間,則\(Time(n)=2\times Time(n/2)+O(n)\),解得\(Time(n)=O(nlog_n)\)

因此算法的總時間複雜度爲\(O(nlog_n)\)

#include <bits/stdc++.h>
using namespace std;
int s[200010];
int last[200010];
int nxt[200010];
map<int,int>be;
map<int,int>wi;
inline bool solve(int l,int r){
    if(l>=r)
    	return 1;
    int x=l,y=r; 
    while(x<=y){
        if(last[x]<l&&nxt[x]>r)
            return solve(l,x-1)&&solve(x+1,r);
        else if(last[y]<l&&nxt[y]>r)
                return solve(l,y-1)&&solve(y+1,r);
        x++,y--;
    }
    return 0;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        be.clear();
        wi.clear();
        for(int i=1;i<=n;i++) {
            scanf("%d",&s[i]);
            if(!be.count(s[i]))last[i]=-1;
            else last[i]=be[s[i]];
            be[s[i]]=i;
        }
        for(int i=n;i>0;i--) {
            if(!wi.count(s[i]))nxt[i]=n+1;
            else nxt[i]=wi[s[i]];
            wi[s[i]]=i;
        }
        if(solve(1,n))
        	printf("non-boring");
        else
        	printf("boring");
    }   
    return 0;
}
相關文章
相關標籤/搜索