将所有串连起来,中间加一个分隔符,二分答案,有连续ht>=mid且每个串中都出现一次就合法,否则不合法,一定要将分隔符特判掉,否则=0会输出1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
char ch=getchar();int f=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') {f=f*10+(ch^48);ch=getchar();}
return f;
}
char s[10100],temp[2005];int tar[8],now,v[15005],ans,n,T,tot;
int sa1[15005],sa2[15005],rk1[15005],rk2[15005];
int *sa,*SA,*rk,*RK,ht[15005];bool vis[8];
bool check(int x)
{
memset(vis,0,sizeof(vis));
tot=1;
for(int i=T;i;i--)
{
if(sa[1]>tar[i])
{
vis[i]=1;
break;
}
}
for(int i=2;i<=n;i++)
{
if(s[sa[i]]=='~')
break;
if(ht[i]>=x)
{
for(int j=T;j;j--)
{
if(sa[i]>tar[j])
{
if(!vis[j])
{
vis[j]=1;
tot++;
if(tot==T)
return 1;
}
break;
}
}
}
else
{
memset(vis,0,sizeof(vis));
for(int j=T;j;j--)
{
if(sa[i]>tar[j])
{
vis[j]=1;
break;
}
}
tot=1;
}
}
return 0;
}
int main()
{
T=read();int l=0,r=20000;
for(int i=1;i<=T;i++)
{
tar[i]=++now;
s[now]='~';
scanf("%s",temp+1);
n=strlen(temp+1);
r=min(r,n);
for(int j=1;j<=n;j++)
{
s[++now]=temp[j];
}
}
n=now;
sa=sa1,SA=sa2;rk=rk1;RK=rk2;
for(int i=1;i<=n;i++) v[s[i]]++;
for(int i=1;i<=200;i++) v[i]+=v[i-1];
for(int i=n;i;i--) sa[v[s[i]]--]=i;
for(int i=1;i<=n;i++) rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
for(int k=1;k<=n;k<<=1)
{
for(int i=1;i<=n;i++) v[rk[sa[i]]]=i;
for(int i=n;i;i--) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i;
for(int i=1;i<=n;i++) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
swap(rk,RK);swap(sa,SA);
if(rk[sa[n]]==n)
break;
}
int k=0;
for(int i=1;i<n;i++)
{
while(s[sa[rk[i]]+k]==s[sa[rk[i]-1]+k]) k++;
ht[rk[i]]=k;
if(k) k--;
}
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
cout<<ans;
}