bzoj 2946: [Poi2000]公共串 — 后缀自动机
Contents
2946: [Poi2000]公共串
Time Limit: 3 Sec Memory Limit: 128 MB
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
HINT
Source
基本上就是SAM的模板题吧
关于SAM kylelv.com/?p=459
#include<map> #include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define inf 1000000007 #define ll long long #define N 4010 int n,m; char s[N]; int fa[N],ch[N][26],l[N],cnt,lst; void ins(int x) { int p,q,np,nq; p=lst;lst=np=++cnt;l[np]=l[p]+1; while(!ch[p][x]&&p) ch[p][x]=np,p=fa[p]; if(!p){fa[np]=1;return;} q=ch[p][x]; if(l[q]==l[p]+1){fa[np]=q;return;} nq=++cnt;l[nq]=l[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; while(ch[p][x]==q&&p) ch[p][x]=nq,p=fa[p]; } int q[N],v[N],ans[N],mx[N]; void pre() { for(int i=1;i<=cnt;i++) v[l[i]]++; for(int i=1;i<=n;i++) v[i]+=v[i-1]; for(int i=cnt;i;i--) q[v[l[i]]--]=i; for(int i=1;i<=cnt;i++) ans[i]=l[i]; } void sol() { scanf("%s",s+1); n=strlen(s+1); memset(mx,0,sizeof(mx)); int p,now=1,len=0,x; for(int i=1;i<=n;i++) { x=s[i]-'a'; while(!ch[now][x]&&now) now=fa[now]; if(!now) now=1,len=0; else len=min(len,l[now])+1,now=ch[now][x]; mx[now]=max(mx[now],len); } for(int i=cnt;i;i--) mx[fa[q[i]]]=max(mx[fa[q[i]]],mx[q[i]]); for(int i=1;i<=cnt;i++) ans[i]=min(ans[i],mx[i]); } int Ans; int main() { scanf("%d",&m); scanf("%s",s+1); lst=cnt=1; n=strlen(s+1); for(int i=1;i<=n;i++) ins(s[i]-'a'); pre(); for(int i=2;i<=m;i++) sol(); for(int i=1;i<=cnt;i++) Ans=max(Ans,ans[i]); printf("%d\n",Ans); return 0; }
发表评论