题意:链接
方法:后缀数组
解析:
首先我们把所有的字符串都链接起来,并且中间加上随意的不同间隔符,加这个是为了防止两个串连接起来对height数组造成影响。
然后我们只需要搞出来height数组。
然后我们需要二分一个答案即可。
验证这个答案是否合理的充要条件是存在一段连续的height值,使得这部分的所有height值均大于该答案。并且该部分包含了所有字符串。
包含该字符串的定义是该字符串有一个后缀存在于该部分中。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 20010
using namespace std;
int n;
int cnt[N],sa[N],t0[N],t1[N],rnk[N],height[N];
char s[N];
void getsa(int m)
{
int *x=t0,*y=t1;
for(int i=0;i<m;i++)cnt[i]=0;
for(int i=0;i<n;i++)cnt[x[i]=s[i]]++;
for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;i--)sa[--cnt[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++)y[p++]=i;
for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(int i=0;i<m;i++)cnt[i]=0;
for(int i=0;i<n;i++)cnt[x[y[i]]]++;
for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];
for(int i=n-1;i>=0;i--)sa[--cnt[x[y[i]]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&sa[i]+k<n&&sa[i-1]+k<n&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if(p==n)break;
m=p;
}
}
void getheight()
{
int k=0;
for(int i=0;i<n;i++)rnk[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(k!=0)k--;
if(!rnk[i])continue;
int j=sa[rnk[i]-1];
while(s[i+k]==s[j+k])k++;
height[rnk[i]]=k;
}
}
int t;
int belong[N];
int hash[6];
bool check(int x)
{
for(int la=1,i=1;i<=n+1;i++)
{
if(height[i]<x||i==n+1)
{
for(int j=1;j<=t;j++)hash[j]=0;
for(int j=la;j<=i-1;j++)hash[belong[sa[j]]]=1;
int flag=0;
for(int j=1;j<=t;j++)if(hash[j]==0){flag=1;break;}
if(!flag)return 1;
la=i;
}
}
return 0;
}
int main()
{
scanf("%d",&t);
int tmp=0;
for(int i=1;i<=t;i++)
{
s[tmp++]='z'+i;
scanf("%s",s+tmp);
tmp=strlen(s);
}
n=tmp;
s[n++]=' ';
int ccc=0;
for(int i=0;i<tmp;i++)
{
if(s[i]<'a'||s[i]>'z')ccc++;
else belong[i]=ccc;
}
getsa(256);
getheight();
int l=0,r=n;
int ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",ans);
}