求多个字符串的最长公共字串
利用后缀数组求解,将所有的字符串连接成一个长的字符串,二分所有字符串中最短的字符串的长度mid为公共前缀的长度,求出所有满足公共前缀长度大于等于mid的后缀,判断所有的字符串是否都包含在这些后缀中,都包含,则mid为一个可行的长度。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200005
int wa[maxn],wb[maxn],wv[maxn],Ws[maxn];
int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(const int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i = 0;i<m;i++)
Ws[i] = 0;
for(i = 0;i<n;i++)
Ws[x[i]=r[i]]++;
for(i = 1;i<m;i++)
Ws[i]+=Ws[i-1];
for(i = n-1;i>=0;i--)
sa[--Ws[x[i]]] = i;
for(j = 1,p = 1;p<n;j*=2,m=p)
{
for(p = 0,i = n-j;i<n;i++)
y[p++] = i;
for(i = 0;i<n;i++)
if(sa[i]>=j)
y[p++] = sa[i] - j;
for(i = 0;i<n;i++)
wv[i] = x[y[i]];
for(i = 0;i<m;i++)
Ws[i] = 0;
for(i = 0;i<n;i++)
Ws[wv[i]]++;
for(i = 1;i<m;i++)
Ws[i]+=Ws[i-1];
for(i = n-1;i>=0;i--)
sa[--Ws[wv[i]]] = y[i];
for(t = x,x = y,y = t,p = 1,x[sa[0]]=0,i = 1;i<n;i++)
x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
int sa[maxn],Rank[maxn],height[maxn];
void calheight(const int *r,int *sa,int n)
{
int i,j,k = 0;
for(i = 1;i<=n;i++)
Rank[sa[i]] = i;
for(i = 0;i<n;height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
}
int str[maxn];
int local[maxn];
bool flag[105];
int solve(int minlen,int n,int cnt)
{
int s = 0,e = minlen,mid,appear,ans = 0;
while(s<=e)
{
memset(flag,0,sizeof(flag));
appear = 0;
mid = (s+e)>>1;
bool tmp = false;
for(int i = 1;i<=n;i++)
{
if(height[i]>=mid)
{
int num = local[sa[i]];
if(!flag[num])
{
appear++;
flag[num] = 1;
}
if(appear==cnt)
{
tmp = true;
break;
}
}
else
{
appear = 0;
memset(flag,0,sizeof(flag));
int num = local[sa[i]];
appear++;
flag[num] = 1;
}
}
if(tmp)
{
s = mid+1;
ans = mid;
}
else
{
e = mid-1;
}
}
return ans;
}
int main()
{
int t,n,minlen=105;
int spe = 500;
char s[200];
for(scanf("%d",&t);t;t--)
{
scanf("%d",&n);
minlen = 105;
int k = 0;
for(int i = 0;i<n;i++)
{
scanf("%s",s);
int len = strlen(s);
if(len < minlen)
minlen = len;
for(int j = 0;j<len;j++)
{
str[k] = s[j];
local[k++] = i;
}
str[k] = spe++;
local[k++] = i;
for(int j = len-1;j>=0;j--)
{
str[k] = s[j];
local[k++] = i;
}
str[k] = spe++;
local[k++] = i;
}
str[k] = 0;
local[k] = n;
da(str,sa,k+1,spe);
calheight(str,sa,k);
int ans = solve(minlen,k,n);
printf("%d\n",ans);
}
}