题意:给了n个字符串,如果有超过n/2的字符串有公共子串,求最长的公共子串,如果有多组解,按字典序输出
思路:可以把这n个字符串连接起来,中间用特殊字符连接,然后构造后缀数组,然后先用二分求出公共子串的最长长度,用height数组和sa数组(sa数组用于判断这部分后缀串包含的字符串数量是否多于n/2)去判定该长度的公共子串是否存在,最后再用height数组把符合条件的公共子串按字典序输出。(刘汝佳的模板竟然照搬都搬错.....)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+1000;
struct S_array
{
int s[maxn],sa[maxn],t[maxn],t2[maxn],c[maxn],n;
void build_sa(int m)
{
int i,*x=t,*y=t2;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=0;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)break;
m=p;
}
}
int rank[maxn],height[maxn];
void getHeight()
{
int i,j,k=0;
for(i=0;i<n;i++)rank[sa[i]]=i;
for(i=0;i<n;i++){
if(k)k--;
if(rank[i]-1<0)
continue;
int j=sa[rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[rank[i]]=k;
}
}
void clear()
{
n=0;
}
}sa;
int n,idx[maxn];
char s[1005];
int ok(int L,int R)
{
int flag[205]={0};
int cnt=0;
for(int i=L;i<R;i++)
if(!flag[idx[sa.sa[i]]])
{
flag[idx[sa.sa[i]]]=1;
cnt++;
}
if(cnt>n/2)
return 1;
return 0;
}
int judge(int len)
{
int L=0,R=1;
for(;R<=sa.n;R++)
{
if(sa.height[R]<len||R==sa.n)
{
if(ok(L,R))
return 1;
L=R;
}
}
return 0;
}
void print_sub(int k,int len)
{
for(int i=k;i<len;i++)
printf("%c",sa.s[i]+'a');
printf("\n");
}
void print(int len)
{
int L=0,R=1;
for(;R<=sa.n;R++)
{
if(sa.height[R]<len||R==sa.n)
{
if(ok(L,R))
print_sub(sa.sa[L],sa.sa[L]+len);
L=R;
}
}
}
void work(int L,int R)
{
int m=(L+R)/2;
if(!judge(1))
{
printf("?\n");
return;
}
while(L<R)
{
if(judge(m))
{
if(L==m)
break;
L=m;
}
else
R=m;
m=(L+R)/2;
}
if(judge(m+1))
m++;
print(m);
}
void add(int c,int k)
{
idx[sa.n]=k;
sa.s[sa.n++]=c;
}
int main()
{
int kase=0;
while(~scanf("%d",&n)&&n)
{
int i,maxlen=0;
sa.clear();
if(kase++>0)
printf("\n");
for(i=0;i<n;i++)
{
scanf("%s",s);
int len=strlen(s);
maxlen=max(maxlen,len);
for(int j=0;j<len;j++)
add(s[j]-'a',i);
add(100+i,n);
}
sa.build_sa(100+n);
sa.getHeight();
work(0,maxlen);
}
}