您的位置:首页 > 其它

bzoj 2946: [Poi2000]公共串 (后缀自动机)

2016-12-20 18:47 369 查看

2946: [Poi2000]公共串

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 783  Solved: 340

[Submit][Status][Discuss]

Description

 
       给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:

l        读入单词

l        计算最长公共子串的长度

l        输出结果
 

Input

 
文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。
 

Output

仅一行,一个整数,最长公共子串的长度。
 

Sample Input

3

abcb

bca

acbc

Sample Output


HINT

Source



[Submit][Status][Discuss]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 20000
using namespace std;
int n,m,cnt,last,root,p,q,np,nq,len;
int fa
,ch
[30],l
,a
,cl
,mn
,ans,pos
,v
;
char s
;
void extend(int x)
{
int c=a[x];
p=last; np=++cnt; last=np;
l[np]=x;
for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
if (!p) fa[np]=root;
else {
int q=ch[p][c];
if (l[q]==l[p]+1) fa[np]=q;
else {
nq=++cnt; l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[nq]);
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
}
void solve()
{
int tmp=0; p=1;
memset(cl,0,sizeof(cl));
for (int i=1;i<=len;i++){
int c=s[i]-'a';
if (ch[p][c]) p=ch[p][c],tmp++;
else {
while (p&&!ch[p][c]) p=fa[p];
if (!p) p=root,tmp=0;
else tmp=l[p]+1,p=ch[p][c];
}
cl[p]=max(cl[p],tmp);
}
for (int i=cnt;i>=1;i--){
int t=pos[i];
mn[t]=min(mn[t],cl[t]);
if (fa[t]&&cl[t]) cl[fa[t]]=l[fa[t]];
}
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
last=root=++cnt;
memset(mn,127,sizeof(mn));
scanf("%s",s+1); len=strlen(s+1);
for (int i=1;i<=len;i++) a[i]=s[i]-'a',extend(i);
if (n==1) {
printf("%d\n",len);
return 0;
}
for (int i=1;i<=cnt;i++) v[l[i]]++;
for (int i=1;i<=len;i++) v[i]+=v[i-1];
for (int i=1;i<=cnt;i++) pos[v[l[i]]--]=i;
for (int i=2;i<=n;i++) {
scanf("%s",s+1); len=strlen(s+1);
solve();
}
for (int i=1;i<=cnt;i++) ans=max(ans,mn[i]);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: