题意:给定 n 个字符串,找到最长的一个子串 s,使得 s 在每个字符串中至少不重叠出现两次,求出这个长度;
分析:将 n 个字符串连接起来,两两之间加上不相同未在正文出现的字符,求一遍后缀数组,然后二分这个最大子串长度判断就好了
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2E5+10;
char s[N];
int n,sa[N],rk[N],oldrk[N<<1],id[N],px[N],cnt[N],ht[N];
int str[N];
void init(){
memset(cnt,0,sizeof(cnt));
}
bool cmp(int x,int y,int w){
return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void da(int s[],int n,int m){
int i,p=0,w,k;
for(i=1;i<=n;++i) ++cnt[rk[i] = s[i]];
for(i=1;i<=m;++i) cnt[i] += cnt[i-1];
for(i=n;i>=1;--i) sa[cnt[rk[i]]--] = i;
for(w=1;w<n;w<<=1,m=p){ //m=p:优化计数排序值域
for(p=0,i=n;i>n-w;--i) id[++p]=i;
for(i=1;i<=n;++i)
if(sa[i]>w) id[++p]=sa[i]-w;
memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;++i) ++cnt[px[i] = rk[id[i]]];
for(i=1;i<=m;++i) cnt[i] += cnt[i-1];
for(i=n;i>=1;--i) sa[cnt[px[i]]--] = id[i];
memcpy(oldrk,rk,sizeof(rk));
for(p=0,i=1;i<=n;++i)
rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
}
for(i=1,k=0;i<=n;++i){
if(k) --k;
while(s[i+k]==s[sa[rk[i]-1]+k]) ++k;
ht[rk[i]]=k;
}
}
int num[15],pre[15],idx[N];
int abs(int x){
return x<0?-x:x;
}
bool judge(int n){
for(int i=1;i<=n;i++){
if(num[i]<2) return 0;
}
return 1;
}
bool check(int len,int cnt,int n){
memset(num,0,sizeof(num));
memset(pre,-1,sizeof(pre));
for(int i=1;i<=cnt;i++){
if(ht[i]>=len){
if(pre[idx[sa[i-1]]]==-1){
num[idx[sa[i-1]]]++;
pre[idx[sa[i-1]]]=sa[i-1];
}
else if(abs(pre[idx[sa[i-1]]]-sa[i-1])>=len){
num[idx[sa[i-1]]]++;
}
if(pre[idx[sa[i]]]==-1){
num[idx[sa[i]]]++;
pre[idx[sa[i]]]=sa[i];
}
else if(abs(pre[idx[sa[i]]]-sa[i])>=len){
num[idx[sa[i]]]++;
}
}
else{
if(judge(n)) return 1;
memset(num,0,sizeof(num));
memset(pre,-1,sizeof(pre));
}
}
return judge(n);
}
int main()
{
int T,i,j,l,r,cnt,len,ANS;
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n);
cnt=0,r=1E7;
for(i=1;i<=n;i++){
scanf("%s",s);
len=strlen(s);
r=min(r,len);
for(j=0;j<len;j++){
idx[++cnt]=i;
str[cnt]=s[j];
}
idx[++cnt]=0;
str[cnt]=i;
}
cnt--;
da(str,cnt,130);
l=1,r/2,ANS=0;
while(l<=r){
int m=(l+r)>>1;
if(check(m,cnt,n)){
ANS=m;
l=m+1;
}
else r=m-1;
}
printf("%d\n",ANS);
}
}