Description
FGD的眼睛瞪得像苹果,他还计划中午回到母舰去他家旁边的咖啡厅去喝一杯呢。看来咖啡是暂时泡汤了。
“据说,为了预防日益增加的逃兵问题,这战机的引擎没有舰长的命令,是无法关闭,只能向前的。”
“好!现在我下令让他关闭!”
“可是,我们都不知道该怎么关掉他。”
……
FGD走到动力舱,一脚踢开在控制台上焦头烂额的工程师,自己坐了上去。
一小时后……
FGD发现每当他想关闭引擎的时候,就会有一大堆乱码跳出来,他便会不由自主地去阅读那一大段无规律的文字,阻止他的正常思维,使得他没有空闲时间去按下对话框的确定。
一天后……
FGD终于有点头绪了,他发现这段文字并不是完全漫无规律的,这段仅仅由小写字母组成的文字可以被分为长度相同的若干行,每行都有一串相同的连续的文字,隐藏在其他乱码中间。FGD以他敏锐的大脑相信,那段最长的被重复的文字一定包含有惊天的大秘密。现在你帮忙告诉他那段文字的长度吧。

Input
输入文件第一行为两个整数nl,表示这段文字共可以分为n行,每行的长度均为l。(1<=n<=10,1<=l<=10000
接下来n行为那n行仅有小写字母组成的文字。

Output
要求输出文件仅包含一行,一个整数,为这n行文字都包含的最长的一段连续的文字的长度。

Sample Input
2 5
ababc
cabac

Sample Output
3

HINT

思路
首先将几个串连在一起,然后把最长不重叠子串改一改就好了。

代码

#include <cstdio>
#include <algorithm>

const int maxn=300000;

char s[maxn+10],t[maxn+10];
int m,len,pos[maxn+10];

struct suffix_array
{
  int rank[maxn+10],sa[maxn+10],sum[maxn+10],tmp[maxn+10],h[maxn+10];

  inline int suffix_sort(int n)
  {
    int m=127,p=1,len=1;
    int* x=rank;
    int* y=tmp;
    for(register int i=1; i<=n; ++i)
      {
    x[i]=s[i];
    y[i]=i;
    ++sum[x[i]];
      }
    for(register int i=1; i<=m; ++i)
      {
    sum[i]+=sum[i-1];
      }
    for(register int i=n; i; --i)
      {
    sa[sum[x[i]]]=i;
    --sum[x[i]];
      }
    while(p<n)
      {
    m=p;
    p=0;
    for(register int i=0; i<=m; ++i)
      {
        sum[i]=0;
      }
    for(register int i=n-len+1; i<=n; ++i)
      {
        ++p;
        y[p]=i;
      }
    for(register int i=1; i<=n; ++i)
      {
        if(sa[i]-len>0)
          {
        ++p;
        y[p]=sa[i]-len;
          }
      }
    for(register int i=1; i<=n; ++i)
      {
        ++sum[x[y[i]]];
      }
    for(register int i=1; i<=m; ++i)
      {
        sum[i]+=sum[i-1];
      }
    for(register int i=n; i; --i)
      {
        sa[sum[x[y[i]]]]=y[i];
        --sum[x[y[i]]];
      }
    std::swap(x,y);
    p=1;
    x[sa[1]]=1;
    for(register int i=2; i<=n; ++i)
      {
        if(!((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+len]==y[sa[i-1]+len])))
          {
        ++p;
          }
        x[sa[i]]=p;
      }
    len<<=1;
      }
    p=0;
    for(register int i=1; i<=n; ++i)
      {
    ++p;
    rank[sa[i]]=p;
      }
    return 0;
  }

  inline int get_height(int n)
  {
    int k=0;
    for(register int i=1; i<=n; ++i)
      {
    if(k)
      {
        --k;
      }
    int j=sa[rank[i]-1];
    while(s[i+k]==s[j+k])
      {
        ++k;
      }
    h[rank[i]]=k;
      }
    return 0;
  }

  inline int judge(int x,int n)
  {
    int b[11],cnt=1;
    for(register int i=1; i<=m; ++i)
      {
    b[i]=0;
      }
    b[pos[sa[1]]]=1;
    for(int i=2; i<=n; ++i)
      {
    if(h[rank[sa[i]]]<x)
      {
        for(register int j=1; j<=m; ++j)
          {
        b[j]=0;
          }
        cnt=1;
        b[pos[sa[i]]]=1;
      }
    else if(!b[pos[sa[i]]])
      {
        b[pos[sa[i]]]=1;
        ++cnt;
      }
    if(cnt>=m)
      {
        return 1;
      }
      }
    return 0;
  }

  inline int work(int n)
  {
    suffix_sort(n);
    get_height(n);
    int left=0,right=len;
    while(left<=right)
      {
    int mid=(left+right)>>1;
    if(judge(mid,n))
      {
        left=mid+1;
      }
    else
      {
        right=mid-1;
      }
      }
    return left-1;
  }
};

suffix_array sa;

int main()
{
  scanf("%d%d",&m,&len);
  int x=0;
  for(register int i=1; i<m; ++i)
    {
      scanf("%s",t+1);
      for(register int j=1; j<=len; ++j)
    {
      s[x+j]=t[j];
      pos[x+j]=i;
    }
      x+=len+1;
      s[x]='~';
    }
  scanf("%s",t+1);
  for(register int i=1; i<=len; ++i)
    {
      s[x+i]=t[i];
      pos[x+i]=m;
    }
  x+=len;
  printf("%d\n",sa.work(x));
  return 0;
}