1. 程式人生 > >解題:NOI 2016 優秀的拆分

解題:NOI 2016 優秀的拆分

題面

其實題目不算很難,但是我除錯的時候被玄學了,for迴圈裡不寫空格會RE,寫了才能過。神**調了一個多小時是這麼個不知道是什麼的玩意(真事,可以問i207M=。=),心態爆炸

發現我們只要找AA或者BB就行了,因為另一半反過來再做一次然後拼起來就可以了,那麼就設$stp[i]$表示從$i$開始有多少個$AA$這樣的串,$edp[i]$表示在$i$結束有多少個$AA$這樣的串。一個個位置暴力求是$O(n^2)$的,可以得95pts(霧。

AC做法是一種巧妙(套路?畢竟我做題少)的做法。列舉一個len把串分成長度為$len$的段,然後發現形如$AA$的字串一定至少跨過了兩個分界點,那麼我們求一下這兩個分界點的$LCP$和$LCS$,看看是不是超過$len$即可,然後具體的貢獻可以用差分實現,時間複雜度$O(n\log n)$(不知道為啥$n$只出了30000,可能是為了放雜湊+二分的$O(n\log^2 n)$過去?)。

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int N=30005,K=16;
  7 struct a
  8 {
  9     char str[N];
 10     int sec[N],bkt[N];
 11     int sar[N],rnk[N],hgt[N],st[N][K];
 12     int len,siz;
13 void Set() 14 { 15 len=0,siz=30; 16 memset(sec,0,sizeof sec); 17 memset(rnk,0,sizeof rnk); 18 } 19 void Prework() 20 { 21 register int i; 22 for(i=1;i<=len;i++) 23 rnk[i]=str[i]-'a'+1,sec[i]=i; 24 } 25 void
Basenum_Sort() 26 { 27 register int i; 28 for(i=1;i<=siz;++i) bkt[i]=0; 29 for(i=1;i<=len;++i) ++bkt[rnk[i]]; 30 for(i=1;i<=siz;++i) bkt[i]+=bkt[i-1]; 31 for(i=len;i>=1;--i) sar[bkt[rnk[sec[i]]]--]=sec[i]; 32 } 33 void Suffix_Sort() 34 { 35 register int i; 36 int cnt=0,pw=1; 37 Basenum_Sort(); 38 while(cnt<len) 39 { 40 cnt=0; 41 for(i=1;i<=pw;i++) sec[++cnt]=len-pw+i; 42 for(i=1;i<=len;i++) if(sar[i]>pw) sec[++cnt]=sar[i]-pw; 43 Basenum_Sort(); swap(rnk,sec); rnk[sar[1]]=cnt=1; 44 for(i=2;i<=len;i++) 45 cnt+=(sec[sar[i-1]]!=sec[sar[i]]||sec[sar[i-1]+pw]!=sec[sar[i]+pw]),rnk[sar[i]]=cnt; 46 pw<<=1,siz=cnt; 47 } 48 } 49 void Getting_Height() 50 { 51 register int i,p=0; 52 for(i=1;i<=len;i++) 53 if(rnk[i]!=1) 54 { 55 int r=sar[rnk[i]-1]; 56 while(str[r+p]==str[i+p]) p++; 57 hgt[rnk[i]]=p; if(p>0) p--; 58 } 59 hgt[1]=0; 60 } 61 void Building_Table() 62 { 63 register int i,j; 64 for(i=1;i<=len;i++) 65 st[i][0]=hgt[i]; 66 int lgg=log2(len); 67 for(i=1;i<=lgg;i++) 68 for(j=1;j<=len-(1<<i)+1;j++) 69 st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]); 70 } 71 int LCP_Query(int x,int y) 72 { 73 int xx=rnk[x],yy=rnk[y],lgg; 74 if(xx>yy) swap(xx,yy); xx++,lgg=log2(yy-xx+1); 75 return min(st[xx][lgg],st[yy-(1<<lgg)+1][lgg]); 76 } 77 }SA[2]; 78 int n,lth,stp[N],edp[N]; 79 void Init() 80 { 81 SA[0].Set(),SA[1].Set(); 82 memset(stp,0,sizeof stp); 83 memset(edp,0,sizeof edp); 84 } 85 int main() 86 { 87 register int i,j,k,h; 88 scanf("%d",&n); 89 for(i=1;i<=n;i++) 90 { 91 Init(); scanf("%s",SA[0].str+1); 92 SA[0].len=SA[1].len=lth=strlen(SA[0].str+1); 93 for(j=1;j<=lth;j++) 94 SA[1].str[j]=SA[0].str[lth-j+1]; 95 for(j=0;j<=1;j++) 96 { 97 SA[j].Prework(); 98 SA[j].Suffix_Sort(); 99 SA[j].Getting_Height(); 100 SA[j].Building_Table(); 101 } 102 for(j=1;j<=lth/2;j++) 103 { 104 for(k=j,h=2*j;h<=lth;k+=j,h+=j) 105 { 106 int l1=min(SA[0].LCP_Query(k,h),j); 107 int l2=min(SA[1].LCP_Query(lth-k+1,lth-h+1),j); 108 if(l1+l2>j) 109 { 110 stp[k-l2+1]++,edp[h-l2+j]++; 111 stp[k+l1-j+1]--,edp[h+l1]--; 112 } 113 } 114 } 115 long long ans=0; 116 for(j=1;j<=lth;j++) 117 stp[j]+=stp[j-1],edp[j]+=edp[j-1]; 118 for(j=1;j<lth;j++) 119 ans+=1ll*stp[j+1]*edp[j]; 120 printf("%lld\n",ans); 121 } 122 return 0; 123 }
View Code