1. 程式人生 > >[Cerc2012]Non-boring sequences

[Cerc2012]Non-boring sequences

Description

定義一個序列是不無聊的,當且僅當它的所有子區間都存在一個獨一無二的數字,即每個子區間裡至少存在一個數字只出現過一次。給定一個長度為\(N(N\leq2\times 10^5)\)的序列,請判斷它是不是無聊的。

Solution

對於每個位置\(i\),先求出\(pre[i],nxt[i]\)表示在\(i\)之前第一個和在\(i\)之後第一個權值等於\(val[i]\)的位置。

如果一個區間\([l,r]\)不是無聊的,一個必要條件是存在\(i\in [l,r]\)滿足\(pre[i]<l\;\land \;nxt[i]>r\)。這樣所有跨過\(i\)的區間都是不無聊的,接著判斷\([l,i)\)

\((i,r]\)就行了。

這啟發我們分治解決問題。

每次在\([l,r]\)內找到一個滿足上述條件的\(i\),然後遞迴處理兩邊的區間。

複雜度看上去貌似很爆炸,因為沒有每次從中間切開的話就不能保證遞迴層數是\(O(\log)\)級別了。

然而有個很玄妙的結論是\(T(n)=max\left\{ T(k)+T(n-k)+min(k,n-k)\right\}\approx O(n\log n)\)

這裡證明寫的很清晰。

說到底,我們不斷拆分這個過程,分開後就不會再合併,而且每次拆開的複雜度就是拆成的兩個序列中較小的一個,很自然地想到把這個過程倒過來,那麼這就是一個啟發式合併的過程,顯然時間複雜度就是\(O(n\log n)\)

本地記得開棧!

Code

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cctype>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using std::min;
using std::max;
using std::swap;
using std::vector;
const int N=2e5+5;
typedef double db;
typedef long long ll;
#define pb(A) push_back(A)
#define pii std::pair<int,int>
#define mp(A,B) std::make_pair(A,B)

int n,val[N],las[N];
int nxt[N],pre[N],g[N];

int getint(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=X*10+ch-48,ch=getchar();
    if(w) return -X;return X;
}

bool solve(int l,int r){
    if(l>r) return 1;
    if(l==r) return 1;
    for(int i=l;i<=r;i++){
        if(pre[i]<l and nxt[i]>r)
            return solve(l,i-1) and solve(i+1,r);
    }
    return 0;
}

signed main(){
    int T=getint();
    while(T--){
        int n=getint();
        for(int i=1;i<=n;i++) g[i]=val[i]=getint();
        std::sort(g+1,g+1+n);int len=std::unique(g+1,g+1+n)-g-1;
        for(int i=1;i<=n;i++){
            val[i]=std::lower_bound(g+1,g+1+len,val[i])-g;
            pre[i]=las[val[i]];las[val[i]]=i;
        } for(int i=1;i<=len;i++) las[i]=n+1;
        for(int i=n;i;i--){
            nxt[i]=las[val[i]];
            las[val[i]]=i;
        } for(int i=1;i<=len;i++) las[i]=0;
        solve(1,n)?printf("non-boring\n"):printf("boring\n");
    } return 0;
}