题目大意:给出N (N≤10)个长度不超过100000的字符串,求他们的最长公共连续子串。
用后缀数组加二分可在nlog求解,但会了后缀自动机就可以O(n)求解,先对一个串建sam,再匹配余下的,最后沿fa边dfs即可。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n;char s[N];
struct Sam{
struct gg{
int mx,fa,nxt[26];
}node[N*2];
int cnt,las,tax[N*2],res[N*2],ans[N*2],id[N*2];
void init()
{
memset(ans,127,sizeof ans);
las=cnt=1;
}
void add(int x)
{
int p,np,t,nt;
p=las,np=las=++cnt;
node[np].mx=node[p].mx+1;
while(p&&!node[p].nxt[x])
{
node[p].nxt[x]=np;
p=node[p].fa;
}
if(!p)node[np].fa=1;
else
{
t=node[p].nxt[x];
if(node[t].mx==node[p].mx+1)
node[np].fa=t;
else
{
nt=++cnt;node[nt].mx=node[p].mx+1;
memcpy(node[nt].nxt,node[t].nxt,sizeof node[t].nxt);
node[nt].fa=node[t].fa;
node[t].fa=node[np].fa=nt;
for(;node[p].nxt[x]==t;p=node[p].fa)node[p].nxt[x]=nt;
}
}
}
void rsort()
{
for(int i=1;i<=cnt;i++)tax[node[i].mx]++;
for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1];
for(int i=cnt;i>=1;i--)id[tax[node[i].mx]--]=i;
}
void match(char *s)
{
memset(res,0,sizeof res);
int len=strlen(s+1),ps=1,nx,ft=0;
for(int i=1;i<=len;i++)
{
nx=s[i]-'a';
if(node[ps].nxt[nx])ps=node[ps].nxt[nx],++ft;
else
{
while(ps&&!node[ps].nxt[nx])ps=node[ps].fa;
if(ps==0)ps=1,ft=0;
else ft=node[ps].mx+1,ps=node[ps].nxt[nx];
}
res[ps]=max(res[ps],ft);
}
for(int i=cnt;i>=1;i--)
{
ps=id[i];
ans[ps]=min(ans[ps],res[ps]);
res[node[ps].fa]=max(res[node[ps].fa],res[ps]);
}
}
void solve()
{
int moha=0;
for(int i=1;i<=cnt;i++)
moha=max(moha,min(node[i].mx,ans[i]));
cout<<moha;
}
}sam;
int main()
{
int len;
sam.init();
int cc=0;
while(~scanf("%s",s+1))
{
++cc;if(s[1]=='P')break;
if(cc==1)
{
len=strlen(s+1);
for(int j=1;j<=len;j++)
sam.add(s[j]-'a');
sam.rsort();
}
else sam.match(s);
}
sam.solve();
}