1. 程式人生 > >【bzoj 4059】Non-boring sequences(分治+啟發式分裂)

【bzoj 4059】Non-boring sequences(分治+啟發式分裂)

傳送門biu~
我們可以把相同的數字用雙向連結串列串起來,pre[x]為x位置之前第一個和x位置數字相同的位置,nexxx位置之後第一個和x位置數字相同的位置。對於區間[l,r],當存在位置x使prex<lnexx>r。則這個區間是不無聊的,而且區間[l,r]的所有包含x位置的子區間也是不無聊的,所以可以遞迴判斷區間[l,x1][x+1,r]
對於區間[l,r],如果按l~r的順序列舉滿足prex<lnexx>

r的位置x,那麼最壞的情況下,位置x在位置r處。這樣就會向下遞迴n層。時間複雜度O(n2)
而如果對於區間[l,r],從兩邊向中間列舉,那麼最壞的情況下,位置x在位置l+r2處,
這樣會向下遞迴logn層,時間複雜度O(nlogn)。這就是啟發式分裂的思想。
那麼再加個map應該是O(nlog2n)。(劃掉)

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[200005];
map<int,int>head,nex,pre;
bool
check(int L,int R){ if(L>R) return true; int x=L-1,y=R+1; while(++x<=--y){ if(pre[x]<L && nex[x]>R) return (check(L,x-1) && check(x+1,R)); if(pre[y]<L && nex[y]>R) return (check(L,y-1) && check(y+1,R)); } return
false; } int main(){ int T; scanf("%d",&T); while(T--){ head.clear(); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); pre[i]=head[a[i]]; nex[i]=n+1; nex[head[a[i]]]=i; head[a[i]]=i; } printf(check(1,n)?"non-boring\n":"boring\n"); } return 0; }