后缀数组。
解决多个字符串的最长公共子串。
采用对长度的二分,将子串按height分组,每次判断是否在每个字符串中都出现过。
复杂度O(NlogN)
By:大奕哥
1 #include<cstring> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<iostream> 6 #define rank fank 7 using namespace std; 8 const int N=1000005; 9 int r[N],wa[N],wb[N],wv[N],wu[N],sa[N],rank[N],height[N],bel[N],cnt; 10 int cmp(int *r,int a,int b,int l) 11 { 12 return r[a]==r[b]&&r[a+l]==r[b+l]; 13 } 14 void da(int *r,int *sa,int n,int m) 15 { 16 int i,j,p;int *x=wa,*y=wb; 17 for(i=0;i<m;++i)wu[i]=0; 18 for(i=0;i<n;++i)wu[x[i]=r[i]]++; 19 for(i=1;i<m;++i)wu[i]+=wu[i-1]; 20 for(i=n-1;i>=0;--i)sa[--wu[x[i]]]=i; 21 for(j=1,p=1;p<n;j<<=1,m=p) 22 { 23 for(p=0,i=n-j;i<n;++i)y[p++]=i; 24 for(i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j; 25 for(i=0;i<n;++i)wv[i]=x[y[i]]; 26 for(i=0;i<m;++i)wu[i]=0; 27 for(i=0;i<n;++i)wu[wv[i]]++; 28 for(i=0;i<m;++i)wu[i]+=wu[i-1]; 29 for(i=n-1;i>=0;--i)sa[--wu[wv[i]]]=y[i]; 30 for(swap(x,y),p=1,x[sa[0]]=0,i=1;i<n;++i) 31 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 32 } 33 return; 34 } 35 void calcHeight(int *rank,int *sa,int n) 36 { 37 int i,j,k=0; 38 for(i=1;i<=n;++i)rank[sa[i]]=i; 39 for(i=0;i<n;height[rank[i++]]=k) 40 for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];++k); 41 return ; 42 } 43 char s[N],ans[N]; 44 bool v[4005]; 45 int tot,num; 46 bool check(int x,int n) 47 { 48 memset(v,0,sizeof(v)); 49 for(int i=2;i<=n;++i) 50 { 51 if(height[i]<x){cnt=0;memset(v,0,sizeof(v));} 52 else 53 { 54 if(v[bel[sa[i-1]]]==0){ 55 cnt++;v[bel[sa[i-1]]]=1; 56 } 57 if(v[bel[sa[i]]]==0){ 58 cnt++;v[bel[sa[i]]]=1; 59 } 60 if(cnt==num) 61 { 62 for(int j=0;j<x;++j) 63 ans[j]=r[sa[i]+j]; 64 ans[x]='\0'; 65 return 1; 66 } 67 } 68 } 69 return 0; 70 } 71 int main() 72 { 73 while(~scanf("%d",&num)&&num) 74 { 75 int len=0; 76 for(int i=0;i<num;++i) 77 { 78 scanf("%s",s); 79 int n=strlen(s); 80 for(int j=0;j<n;++j) 81 { 82 r[len]=s[j];bel[len]=i;++len; 83 } 84 r[len]=200+i;bel[len]=200+i;++len; 85 } 86 --len;r[len]=0; 87 da(r,sa,len+1,5000); 88 calcHeight(rank,sa,len); 89 int as=0,l=1,r=len; 90 while(l<=r) 91 { 92 int mid=l+r>>1; 93 if(check(mid,len))as=1,l=mid+1; 94 else r=mid-1; 95 } 96 if(as)printf("%s\n",ans); 97 else 98 printf("IDENTITY LOST\n"); 99 } 100 return 0; 101 }
Ps:wa了好多遍,因为插进去的ascII码值没有选好,附一张ascII表。