1. 程式人生 > >【BZOJ 4059】 (分治暴力|掃描線+線段樹)

【BZOJ 4059】 (分治暴力|掃描線+線段樹)

【分析】

  這題我是不會往掃描線方向想的。感覺很神奇。

  首先對於每個a[i]求前一個同色的位置$last$和後一個的位置$next$,顯然左端點在[last+1,i]右端點在[i,next-1]的都是可以的。

  那麼把左端點當成x,右端點當成y,區間就表示成了平面上的一個點,可行區間集就是一個矩形,最後看看n個矩形是否把上三角覆蓋。

  【這個把這題複雜化了,其實有更簡單的方法所以我沒打這個哦

  很容易想到暴力。

  如果序列non-boring,必定有一個數值只出現了一次,找到他的位置i【可能有多個,先隨便找一個】,

  那麼區間跨越i的都可以的嘛,所以只需判斷[l,i-1]和[i+1,r]即可。

  就把區間分治了。

  但是時間複雜度???

  網上的神犇們說,從左右兩端向中間暴力列舉,用$next$和$last$$O(1)$判斷即可。

  是nlogn的。

  因為:$T(n)=max{T(k)+T(n-k)+min(n,n-k)}=O(nlogn)$

  直觀證明:

  我們考慮每個對時間複雜度有貢獻的下標,它一定屬於兩段中比較小的那一段,於是。。

  每次每個下標被算一次,它的所在塊就會縮小一倍,那麼顯然每個下標的貢獻就是O(logn),它的總時間複雜度就是O(nlogn)。

  ORZORZ。。

 1 #include<cstdio>
 2 #include<cstdlib>
 3
#include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 200010 8 9 struct node{int x,id;}t[Maxn]; 10 bool cmp(node x,node y) {return x.x<y.x;} 11 int a[Maxn],nt[Maxn],lt[Maxn],ft[Maxn]; 12 13 bool ffind(int l,int r) 14 { 15 if(l>=r) return
1; 16 int t=-1; 17 for(int i=0;i<=r-l+1;i++) 18 { 19 if(l+i>r-i) break; 20 if(nt[l+i]>r&&lt[l+i]<l) {t=l+i;break;} 21 if(nt[r-i]>r&&lt[r-i]<l) {t=r-i;break;} 22 } 23 if(t==-1) return 0; 24 return ffind(l,t-1)&&ffind(t+1,r); 25 } 26 27 int main() 28 { 29 int T; 30 scanf("%d",&T); 31 while(T--) 32 { 33 int n; 34 scanf("%d",&n); 35 for(int i=1;i<=n;i++) 36 { 37 scanf("%d",&t[i].x);t[i].id=i; 38 } 39 sort(t+1,t+1+n,cmp); 40 a[t[1].id]=1;int p=1; 41 for(int i=1;i<=n;i++) 42 { 43 if(t[i].x!=t[i-1].x) p++; 44 a[t[i].id]=p; 45 } 46 for(int i=1;i<=p;i++) ft[i]=n+1; 47 for(int i=n;i>=1;i--) nt[i]=ft[a[i]],ft[a[i]]=i; 48 for(int i=1;i<=p;i++) ft[i]=0; 49 for(int i=1;i<=n;i++) lt[i]=ft[a[i]],ft[a[i]]=i; 50 if(ffind(1,n)) printf("non-boring\n"); 51 else printf("boring\n"); 52 } 53 return 0; 54 }
View Code

2017-04-25 08:38:03