传送门:SPOJ - PHRASES(后缀数组+二分)
题意:给你n个字符串,找出一个最长的子串,他必须在每次字符串中都出现至少两次。
题解:被自己蠢哭...记录一下自己憨憨的操作,还一度质疑评测鸡(哭...
首先是多个字符串的常规操作(目前写的题少,见到的都是这样)连成一个字符串,中间用不同的且没出现过的字符隔开。然后后缀数组求出sa数组和height数组,二分子串长度,用mx数组记录该串中的这个子串的起点最大值,mi数组记录最小值,如果所有串中的mx-mi都>=k说明这个长度可以。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<iostream> 5 #include<cmath> 6 #include<cstring> 7 using namespace std; 8 9 //sa:字典序中排第i位的起始位置在str中第sa[i] sa[1~n]为有效值 10 11 //rnk:就是str第i个位置的后缀是在字典序排第几 rnk[0~n-1]为有效值 12 13 //height:字典序排i和i-1的后缀的最长公共前缀 height[2~n]为有效值,第二个到最后一个 14 15 const int INF=0x3f3f3f3f; 16 const int maxn = 1e5+10; 17 int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn]; 18 int rnk[maxn],height[maxn],be[maxn]; 19 char s[maxn]; 20 int r[maxn],n,len,mx[maxn],mi[maxn]; 21 22 int cmp(int *r,int a,int b,int k) 23 { 24 return r[a]==r[b]&&r[a+k]==r[b+k]; 25 } 26 27 void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长 28 { 29 int i,j,p,*x=wa,*y=wb,*t; 30 for(i=0; i<m; i++) wsf[i]=0; 31 for(i=0; i<=n; i++) wsf[x[i]=r[i]]++; 32 for(i=1; i<m; i++) wsf[i]+=wsf[i-1]; 33 for(i=n; i>=0; i--) sa[--wsf[x[i]]]=i; 34 p=1; 35 j=1; 36 for(; p<=n; j*=2,m=p){ 37 for(p=0,i=n+1-j; i<=n; i++) y[p++]=i; 38 for(i=0; i<=n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; 39 for(i=0; i<=n; i++) wv[i]=x[y[i]]; 40 for(i=0; i<m; i++) wsf[i]=0; 41 for(i=0; i<=n; i++) wsf[wv[i]]++; 42 for(i=1; i<m; i++) wsf[i]+=wsf[i-1]; 43 for(i=n; i>=0; i--) sa[--wsf[wv[i]]]=y[i]; 44 swap(x,y); 45 x[sa[0]]=0; 46 for(p=1,i=1; i<=n; i++) 47 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++; 48 } 49 } 50 51 void getheight(int *r,int n)//n为添加0后的总长 52 { 53 int i,j,k=0; 54 for(i=1; i<=n; i++) rnk[sa[i]]=i; 55 for(i=0; i<n; i++){ 56 if(k) 57 k--; 58 else 59 k=0; 60 j=sa[rnk[i]-1]; 61 while(r[i+k]==r[j+k]) 62 k++; 63 height[rnk[i]]=k; 64 } 65 } 66 67 bool check(int k) 68 { 69 for(int j=0;j<n;j++) mx[j]=-INF,mi[j]=INF; //一开始忘记初始化 70 for(int i=2;i<=len;i++){ 71 if(height[i]>=k){ 72 mx[be[sa[i]]]=max(mx[be[sa[i]]],sa[i]); 73 mi[be[sa[i]]]=min(mi[be[sa[i]]],sa[i]); 74 mx[be[sa[i-1]]]=max(mx[be[sa[i-1]]],sa[i-1]); 75 mi[be[sa[i-1]]]=min(mi[be[sa[i-1]]],sa[i-1]); //没眼睛写成了sa[i] 76 } 77 else{ 78 int j=0; 79 for(j=0;j<n;j++) mx[j]=-INF,mi[j]=INF; 80 mx[be[sa[i]]]=sa[i],mi[be[sa[i]]]=sa[i]; 81 } 82 int j=0; 83 for(j=0;j<n;j++){ 84 if(mx[j]-mi[j]<k) break; 85 } 86 if(j==n) return true; 87 } 88 return false; 89 } 90 91 int main() 92 { 93 ios::sync_with_stdio(false); 94 cin.tie(0); 95 cout.tie(0); 96 int t; 97 cin>>t; 98 while(t--){ 99 cin>>n; 100 len=0; 101 for(int i=0;i<n;i++){ 102 cin>>s+len; 103 int p=strlen(s+len); 104 for(int j=0;j<p;j++){ 105 r[j+len]=s[j+len]-'a'+1; 106 be[len+j]=i; 107 } 108 len+=p; 109 if(i!=n-1){ 110 be[len]=i; 111 r[len++]=i+100; 112 } 113 } 114 r[len]=0; 115 getsa(r,sa,len,200); 116 getheight(r,len); 117 int l=0,r=min(len,10000); 118 int ans=0; 119 while(l<=r){ 120 int mid=l+r>>1; 121 if(check(mid)){ 122 ans=mid; 123 l=mid+1; 124 } 125 else r=mid-1; 126 } 127 cout<<ans<<endl; 128 } 129 return 0; 130 }