您的位置:首页 > 其它

bzoj2946 [Poi2000]公共串 后缀自动机

2017-07-23 10:51 267 查看
原来2000年就有SAM了,害怕

先对第一个串建一个SAM,然后把其他串在上面匹配,得出每个状态的最大匹配长度,然后对每个状态取所有串的最小值,这就是最长公共子串,然后对所有子串求个mx就好了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
int ch
[30],fa
,mx
,ans
,l
;
int b
,c
;
char s
;
int n,m,cnt,last;
inline void ins(int x)
{
int p,q,np,nq;
p=last,last=np=++cnt;
l[np]=l[p]+1;
for(;!ch[p][x]&&p;p=fa[p])ch[p][x]=np;
if (!p)fa[np]=1;
else
{
q=ch[p][x];
if (l[q]==l[p]+1)fa[np]=q;
else
{
nq=++cnt;
l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
}
inline void pre()
{
fo(i,1,cnt)b[l[i]]++;
fo(i,1,n)b[i]+=b[i-1];
fo(i,1,cnt)c[b[l[i]]--]=i;
fo(i,1,cnt)ans[i]=l[i];
}
inline void solve()
{
memset(mx,0,sizeof(mx));
int x=1,len=0;
fo(i,1,n)
{
s[i]-='a';
for(;!ch[x][s[i]]&&x;x=fa[x]);
if (!x)x=1,len=0;
else len=min(len,l[x])+1,x=ch[x][s[i]];
mx[x]=max(mx[x],len);
}
fd(i,cnt,1)mx[fa[c[i]]]=max(mx[fa[c[i]]],mx[c[i]]);
fo(i,1,cnt)ans[i]=min(ans[i],mx[i]);
}
int main()
{
scanf("%d",&m);
scanf("%s",s+1);
n=strlen(s+1);
last=cnt=1;
fo(i,1,n)ins(s[i]-'a');
pre();
fo(i,1,m-1)
{
scanf("%s",s+1);
n=strlen(s+1);
solve();
}
int ans1=0;
fo(i,1,cnt)ans1=max(ans1,ans[i]);
printf("%d\n",ans1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: