1. 程式人生 > >BZOJ4698 [SDOI2008] Sandy的卡片 - 後綴數組,二分

BZOJ4698 [SDOI2008] Sandy的卡片 - 後綴數組,二分

卡片 bre pre == body blog zoj syn 進行

題意:求在N個串中都出現的最長子串 的長度

很容易想到二分轉化為判定性問題。考慮長度M,我們按照長度M進行分組,每個組內進行答案驗證,即檢查組內是否有N個串的後綴都出現。

時間復雜度O(LlogM)

其實是個經典題。

二分時候記得初始化!

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct SA {
 5     int str[2100005];
 6     int x[2100005],y[2100005],u[2100005],v[2100005],r[2100005],o[2100005],hei[2100005],m=2100000,n,a[2100005];
 7     void
build(int p,int l,int r){ 8 if(l==r) a[p]=hei[l]; 9 else build(p*2,l,(l+r)/2),build(p*2+1,(l+r)/2+1,r),a[p]=min(a[p*2],a[p*2+1]); 10 } 11 int query(int p,int l,int r,int ql,int qr){ 12 if(l>qr||r<ql) return 1e+9; 13 if(l>=ql&&r<=qr) return a[p];
14 return min(query(p*2,l,(l+r)/2,ql,qr),query(p*2+1,(l+r)/2+1,r,ql,qr)); 15 } 16 void calc(){ 17 int i,j,k=0; 18 for(i=1;i<=n;hei[r[i++]]=k) 19 for(k?k--:0,j=x[r[i]-1];str[i+k]==str[j+k];k++); 20 } 21 int solve(){ 22 memset(r,0,sizeof r); 23 for
(int i=1;i<=n;i++) u[str[i]]++; 24 for(int i=1;i<=m;i++) u[i]+=u[i-1]; 25 for(int i=n;i>=1;i--) x[u[str[i]]--]=i; 26 r[x[1]]=1; 27 for(int i=2;i<=n;i++) r[x[i]]=r[x[i-1]]+((str[x[i]]-str[x[i-1]])?1:0); 28 for(int l=1;r[x[n]]<n;l<<=1) { 29 memset(u,0,sizeof u); memset(v,0,sizeof v); memcpy(o,r,sizeof r); 30 for(int i=1;i<=n;i++) u[r[i]]++, v[(i+l<=n)?r[i+l]:0]++; 31 for(int i=1;i<=n;i++) u[i]+=u[i-1], v[i]+=v[i-1]; 32 for(int i=n;i>=1;i--) y[v[(i+l<=n)?r[i+l]:0]--]=i; 33 for(int i=n;i>=1;i--) x[u[r[y[i]]]--]=y[i]; 34 r[x[1]]=1; 35 for(int i=2;i<=n;i++) r[x[i]]=r[x[i-1]]+ 36 ((o[x[i]]!=o[x[i-1]])||(((x[i]+l<=n)?o[x[i]+l]:0)!=((x[i-1]+l<=n)?o[x[i-1]+l]:0))); 37 } 38 calc(); 39 hei[1]=0; 40 } 41 int lcp(int pos1,int pos2) {return query(1,1,n,min(r[pos1],r[pos2])+1,max(r[pos1],r[pos2]));} 42 } sa; 43 44 int n,k; 45 int len[2100005],str[2100005],src[2100005],x[1005],delta; 46 47 int main(){ 48 ios::sync_with_stdio(false); 49 cin>>n; 50 for(int i=1;i<=n;i++) { 51 cin>>len[i]; 52 for(int j=1;j<=len[i];j++) { 53 cin>>str[j]; 54 } 55 for(int j=len[i];j>=2;j--){ 56 str[j]-=str[j-1]; 57 } 58 for(int j=1;j<=len[i];j++){ 59 str[j]+=1000100; 60 } 61 sa.str[len[i-1]]=i; 62 memcpy(sa.str+len[i-1]+1,str+1,len[i]*sizeof(int)); 63 len[i]+=len[i-1]+1; 64 65 } 66 sa.n=len[n]-1; 67 sa.solve(); 68 for(int i=1;i<=n;i++) 69 for(int j=len[i-1]+1;j<=len[i]-1;j++) 70 src[j]=i; 71 int left=1,right=len[n]-1,ans; 72 while(left-right){ 73 memset(x,0,sizeof x); 74 int mid=(left+right)/2; 75 for(int i=1;i<=len[n]-1;i++) { 76 if(sa.hei[i]<mid-1) { 77 int flag=1; 78 for(int j=1;j<=n;j++) 79 if(x[j]==0) { 80 flag=0; 81 break; 82 } 83 if(flag) { 84 ans=mid; 85 break; 86 } 87 memset(x,0,sizeof x); 88 } 89 x[src[sa.x[i]]]++; 90 } 91 if(ans==mid) left=mid+1; 92 else right=mid; 93 } 94 printf("%d\n",ans); 95 }

BZOJ4698 [SDOI2008] Sandy的卡片 - 後綴數組,二分