BZOJ2946: [Poi2000]公共串
2946: [Poi2000]公共串
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 55 Solved: 33
[Submit][Status]
Description
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:
l 读入单词
l 计算最长公共子串的长度
l 输出结果
Input
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。
Output
仅一行,一个整数,最长公共子串的长度。
Sample Input
3
abcb
bca
acbc
abcb
bca
acbc
Sample Output
2
题解:
后缀数组经典做法。
代码:
View Code
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<queue> 11 #include<string> 12 #define inf 1000000000 13 #define maxn 100000 14 #define maxm 500+100 15 #define eps 1e-10 16 #define ll long long 17 #define pa pair<int,int> 18 #define for0(i,n) for(int i=0;i<=(n);i++) 19 #define for1(i,n) for(int i=1;i<=(n);i++) 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 22 #define mod 1000000007 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 28 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 29 return x*f; 30 } 31 int n,m,c[maxn],t1[maxn],t2[maxn],sa[maxn],rk[maxn],h[maxn],a[maxn]; 32 char s[maxn]; 33 bool v[10]; 34 void getsa(int m) 35 { 36 int *x=t1,*y=t2; 37 for0(i,m)c[i]=0; 38 for0(i,n)c[x[i]=s[i]]++; 39 for1(i,m)c[i]+=c[i-1]; 40 for3(i,n,0)sa[--c[x[i]]]=i; 41 for(int k=1;k<=n+1;k<<=1) 42 { 43 int p=0; 44 for2(i,n-k+1,n)y[p++]=i; 45 for0(i,n)if(sa[i]>=k)y[p++]=sa[i]-k; 46 for0(i,m)c[i]=0; 47 for0(i,n)c[x[y[i]]]++; 48 for1(i,m)c[i]+=c[i-1]; 49 for3(i,n,0)sa[--c[x[y[i]]]]=y[i]; 50 swap(x,y);p=0;x[sa[0]]=0; 51 for1(i,n)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p; 52 if(p>=n)break; 53 m=p; 54 } 55 for1(i,n)rk[sa[i]]=i; 56 for(int i=0,k=0,j;i<n;h[rk[i++]]=k) 57 for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++); 58 } 59 bool check(int x) 60 { 61 for(int i=1,j=1;j<=n+1;j++) 62 if(h[j]<x||j==n+1) 63 { 64 for1(k,m)v[k]=0; 65 for2(k,i,j-1)v[a[sa[k]]]=1; 66 bool flag=0; 67 for1(k,m)if(!v[k])flag=1; 68 if(!flag)return 1; 69 i=j; 70 } 71 return 0; 72 } 73 int main() 74 { 75 freopen("input.txt","r",stdin); 76 freopen("output.txt","w",stdout); 77 m=read(); 78 for1(i,m) 79 { 80 s[n]='z'+i; 81 scanf("%s",s+n+1); 82 int t=strlen(s);for2(j,n+1,t-1)a[j]=i; 83 n=t; 84 } 85 s[n]=' '; 86 getsa(128); 87 int l=0,r=n,mid; 88 while(l<=r) 89 { 90 mid=(l+r)>>1; 91 if(check(mid))l=mid+1;else r=mid-1; 92 } 93 printf("%d\n",r); 94 return 0; 95 }