思路
后缀数组
先都拼在一起
二分+height分段
按照小于x的为分界,判断是否有一个分段中包含超过n/2个串
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Node{
int pos,r[2];
}x[200100],midx[200100];
int n,sa[200100],ranks[200100],barrel[200100],height[200100],belong[200100],has[210],numx;
char s[200100],c[200100];
int c_sort(int n,int lim){
for(int i=0;i<2;i++){
memset(barrel,0,sizeof(barrel));
for(int j=1;j<=n;j++)
barrel[x[j].r[i]]++;
for(int j=1;j<=lim;j++)
barrel[j]+=barrel[j-1];
for(int j=n;j>=1;j--)
midx[barrel[x[j].r[i]]--]=x[j];
for(int j=1;j<=n;j++)
x[j]=midx[j];
}
ranks[x[1].pos]=1;
int cnt=1;
for(int i=2;i<=n;i++){
if(x[i].r[0]==x[i-1].r[0]&&x[i].r[1]==x[i-1].r[1])
ranks[x[i].pos]=cnt;
else
ranks[x[i].pos]=++cnt;
}
return cnt;
}
void cal_sa(int n){
for(int i=1;i<=n;i++)
x[i]=(Node){i,s[i],0};
int cnt=c_sort(n,255);
for(int i=1;cnt<n;i<<=1){
for(int j=1;j<=n;j++)
x[j]=(Node){j,(i+j<=n)?ranks[i+j]:0,ranks[j]};
cnt=c_sort(n,cnt);
}
for(int i=1;i<=n;i++)
sa[ranks[i]]=i;
for(int i=1,j=0,k;i<=n;height[ranks[i++]]=j)
for(j?j--:0,k=sa[ranks[i]-1];s[i+j]==s[j+k];j++);
}
// void init(void){
// for(int i=1;i<=n;i++)
// ST[i][0]=height[i];
// for(int i=1;i<20;i++)
// for(int j=1;j<=n;j++)
// ST[j][i]=min(ST[j][i-1],ST[min(j+(1<<(i-1)),n+10)][i-1]);
// }
// int query(int l,int r){
// l=ranks[l];
// r=ranks[r];
// l++;
// if(l>r)
// swap(l,r);
// int k=0;
// while((1<<k+1)<=(r-l+1))
// k++;
// return min(ST[l][k],ST[r-(1<<k)+1][k]);
// }
bool check(int x){
// printf("check %d
",x);
memset(has,0,sizeof(has));
int midnum=0;
has[0]=true;
if(!has[belong[sa[1]]]){
++midnum;
has[belong[sa[1]]]=true;
}
if(midnum>(numx/2)){
return true;
}
for(int i=2;i<=n;i++){
if(height[i]<x){
memset(has,0,sizeof(has));
has[0]=true;
midnum=0;
if(!has[belong[sa[i]]]){
midnum++;
has[belong[sa[i]]]=true;
}
}
else{
if(!has[belong[sa[i]]]){
midnum++;
has[belong[sa[i]]]=true;
}
}
if(midnum>(numx/2)){
return true;
}
}
return false;
}
void print(int x){
memset(has,0,sizeof(has));
int midnum=0,f=1;
has[0]=true;
if(!has[belong[sa[1]]]){
++midnum;
has[belong[sa[1]]]=true;
}
if(midnum>(numx/2)&&f){
f=0;
for(int j=1;j<=x;j++)
putchar(s[sa[1]+j-1]);
putchar('
');
}
for(int i=2;i<=n;i++){
if(height[i]<x){
f=1;
memset(has,0,sizeof(has));
has[0]=true;
midnum=0;
if(!has[belong[sa[i]]]){
midnum++;
has[belong[sa[i]]]=true;
}
}
else{
if(!has[belong[sa[i]]]){
midnum++;
has[belong[sa[i]]]=true;
}
}
if(midnum>(numx/2)&&f){
f=0;
for(int j=1;j<=x;j++)
putchar(s[sa[i]+j-1]);
putchar('
');
}
}
}
void init(void){
memset(s,0,sizeof(s));
memset(height,0,sizeof(height));
memset(sa,0,sizeof(sa));
memset(ranks,0,sizeof(ranks));
memset(belong,0,sizeof(belong));
memset(midx,0,sizeof(midx));
memset(x,0,sizeof(x));
}
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
int cnt=0;
while(scanf("%d",&numx)==1&&numx){
init();
n=0;
cnt++;
if(cnt>1)
putchar('
');
if(numx==1){
scanf("%s",s);
printf("%s
",s);
continue;
}
for(int i=1;i<=numx;i++){
scanf("%s",c+1);
int len=strlen(c+1);
for(int j=1;j<=len;j++){
s[n+j]=c[j];
belong[n+j]=i;
}
n+=len;
s[++n]='z'+i;
belong[n]=0;
}
// for(int i=1;i<=n;i++)
// putchar(s[i]);
// putchar('
');
cal_sa(n);
// for(int i=1;i<=n;i++){
// printf("%d ",height[i]);
// }
// printf("
");
// for(int i=1;i<=n;i++){
// printf("%d ",belong[sa[i]]);
// }
// printf("
");
// printf("ok
");
int l=0,r=n,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid))
l=mid+1,ans=mid;
else
r=mid-1;
}
// printf("ans=%d
",ans);
if(ans==0){
printf("?
");
}
else{
print(ans);
}
}
return 0;
}