【bzoj 4059】Non-boring sequences

傳送門~

解題思路

考慮分治。雖然我覺得就是暴力
對於一個數,左邊第一個與它一樣的數的位置記爲z[i],右邊第一個記爲y[i]。
對於區間[l,r],如果其中存在一個數i,使z[i] < l 並且 y[i] > r,那麼區間[l,r]是一定符合題目中條件的,只要這個區間的子區間[l,i-1]和[i+1,r]也符合條件,區間[l,r]就是不無聊的。於是這麼分治下去就行了。
但是這麼寫會T,確切的說會被卡成 O (n2 )。
在區間[l,r]中枚舉 i 的時候,從兩邊向中間找,這樣枚舉下來就成了O (nlogn )了。

上午發的這篇博客,但是並不清楚複雜度是怎麼證的,然而下午就被zP1nG大佬證出來了%%%
如果每次從左向右枚舉,就可能每層要找的i都在最左邊或最右邊,這樣每層都要枚舉n次,而且要跑n層遞歸,這樣就會變成n2
但是如果每次從兩邊向中間枚舉,就不會掃遍整個序列。最壞的情況是i在序列中間,這時候就會在每一層跑滿n次,但因爲每次序列長度都除以2,所以最多log層,合起來就是最壞O (nlogn )了。

代碼:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
int sh[200005],xi[200005];
int hed[200005];
int s[200005],b[200005];
int n,T;
bool check(int x,int y){
    if(x>y) return 1;
    int lx=x,ly=y;

    while(lx<=ly){
        if(sh[lx]<x && xi[lx]>y) 
        return check(x,lx-1) && check(lx+1,y);
        lx++;
        if(sh[ly]<x && xi[ly]>y)
        return check(x,ly-1) && check(ly+1,y);
        ly--;
    }

    return 0;
}
int main(){
    scanf("%d",&T);
while(T--){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&s[i]);
        b[i]=s[i];hed[i]=0;
    }
    sort(b+1,b+n+1);
    int top=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) s[i]=lower_bound(b+1,b+top+1,s[i])-b;
    for(int i=1;i<=n;i++){
        sh[i]=hed[s[i]];
        hed[s[i]]=i;
    }
    for(int i=1;i<=n;i++) hed[i]=n+1;
    for(int i=n;i>=1;i--){
        xi[i]=hed[s[i]];
        hed[s[i]]=i;
    }
    if(check(1,n)) printf("non-boring\n");
    else printf("boring\n");    
}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章