bzoj 2946: [Poi2000]公共串

来源:互联网 发布:矩阵lu分解例题 编辑:程序博客网 时间:2024/05/03 20:57

Description

 
       给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
任务:
l        读入单词
l        计算最长公共子串的长度
l        输出结果
 

Input

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

Output

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

Sample Input

3
abcb
bca
acbc

Sample Output


首先一点,root到一个结点的pre包含这个节点的所有后缀。 
那么就很好做了!
对第一个串建立后缀自动机。然后跑匹配
到每个节点的len的最大值取最小值,然后再把所有最小值求最大值就是答案了
初始每个节点的ans[i]为step[i],为了防止路径超过根到当前点的最长路径
#include<cstdio>#include<string>#include<cstring>#include<iostream>using namespace std;struct sam{ int son[1000001][26],pre[1000001],step[1000001]; int ans[1000001],v[1000001],q[1000001]; int len[1000001]; int last,tot; sam() {      last=1;      tot=1; } inline void push_back(int v) {      tot++;      step[tot]=v; } inline void prep() {      int i;      for(i=1;i<=tot;i++)           ans[i]=step[i];      for(i=1;i<=tot;i++)           v[step[i]]++;      for(i=1;i<=tot;i++)           v[i]+=v[i-1];      for(i=tot;i>=1;i--)           q[v[step[i]]--]=i; }//基数排序,确定树的遍历      inline void extend(int x)     {          push_back(step[last]+1);          int p=last,np=tot;          while(son[p][x]==0&&p!=0)          {               son[p][x]=np;               p=pre[p];          }          if(p==0)               pre[np]=1;          else          {               int q=son[p][x];               if(step[q]!=step[p]+1)               {                    push_back(step[p]+1);                    int nq=tot;                    //memcpy(son[nq],son[q],sizeof(son[q]));                    int i;                    for(i=0;i<=25;i++)                         son[nq][i]=son[q][i];                    pre[nq]=pre[q];                    pre[q]=pre[np]=nq;                    while(son[p][x]==q)                    {                         son[p][x]=nq;                         p=pre[p];                    }               }               else                    pre[np]=q;          }          last=np;     }     inline void build()     {       string x;          cin>>x;          int lx=x.size();          int i;          for(i=0;i<=lx-1;i++)               extend(x[i]-'a');     }     inline void solve()     {       memset(len,0,sizeof(len));       string x;          cin>>x;          int lx=x.size();          int p=1,tmp=0;          int i;          for(i=0;i<=lx-1;i++)          {               int xt=x[i]-'a';               while(son[p][xt]==0&&p!=0)                    p=pre[p];               if(p==0)               {                    p=1;                    tmp=0;               }               else               {                    tmp=min(tmp,step[p])+1;                    p=son[p][xt];               }               len[p]=max(len[p],tmp);          }          for(i=tot;i>=1;i--)               len[pre[q[i]]]=max(len[pre[q[i]]],len[q[i]]);          for(i=1;i<=tot;i++)               ans[i]=min(ans[i],len[i]);     }}sam;int main(){ int n; scanf("%d",&n);     sam.build();     int i;     sam.prep();     for(i=2;i<=n;i++)          sam.solve();     int ans=0;     for(i=1;i<=sam.tot;i++)          ans=max(ans,sam.ans[i]);     printf("%d\n",ans);     return 0;}


0 0