题解:

后缀数组

把所有的字符串用不同的分隔符连接起来

然后求height,最后二分求长度为mid的子串是否有满足条件的

记录满足条件的所有子串的首位置

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>  
typedef long long LL;  
using namespace std;  
const int N=200000+10;  
int *rank,r[N],sa[N],height[N],size,wa[N],wb[N],wm[N],len[110],pos[N],mark[110];  
char s[N];  
int cmp(int *r,int a,int b,int l)
{  
    return r[a]==r[b]&&r[a+l]==r[b+l];  
} 
void makesa(int *r,int *sa,int n,int m){  
    int *x=wa,*y=wb;  
    for (int i=0;i<m;i++)wm[i]=0;  
    for (int i=0;i<n;i++)wm[x[i]=r[i]]++;  
    for (int i=1;i<m;i++)wm[i]+=wm[i-1];  
    for (int i=n-1;i>=0;i--)sa[--wm[x[i]]]=i;  
    for (int i=0,j=1,p=0;p<n;j=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<m;i++)wm[i]=0;  
        for (i=0;i<n;i++)wm[x[y[i]]]++;  
        for (i=1;i<m;i++)wm[i]+=wm[i-1];  
        for (i=n-1;i>=0;i--)sa[--wm[x[y[i]]]]=y[i];  
        for (t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++)  
         x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;  
     }  
    rank=x;  
}  
  
void calheight(int *r,int *sa,int n)
{  
    for (int i=0,j=0,k=0;i<n;height[rank[i++]]=k)
     for (k?--k:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);  
}  
int check(int mid,int n,int k)
{  
    memset(mark,false,sizeof mark);  
    int num=0,ans=0;  
    for (int i=1;i<=n;i++)
     {  
         if (height[i]>=mid)
         {  
            for (int j=1;j<=size;j++)
             {   
                if (sa[i]>len[j-1]&&sa[i]<len[j])ans+=(mark[j]?0:1),mark[j]=1;  
                if (sa[i-1]>len[j-1]&&sa[i-1]<len[j])ans+=(mark[j]?0:1),mark[j]=1;  
             }  
         }
        else
         {  
            if (ans>k/2)pos[++num]=sa[i-1];   
            ans=0;  
            memset(mark,false,sizeof mark);  
         }  
     }  
    if (ans>k/2)pos[++num]=sa[n];  
    if (num){pos[0]=num;return 1;}   
    return 0;  
}  
int main()
{  
    int k,n,num=0;  
    len[0]=-1;   
    while(scanf("%d",&k),k)
     {  
        pos[0]=size=n=0;   
        for(int i=0;i<k;i++)
         {  
            scanf("%s",s+n);  
            for(;s[n]!='\0';n++)r[n]=s[n];  
            r[len[++size]=n++]=300+i;   
         }  
        r[n-1]=0;  
        makesa(r,sa,n,400);  
        calheight(r,sa,n-1);  
        int L=1,R=n;  
        while (L<=R)
         {  
            int mid=L+R>>1;  
            if(check(mid,n,k))L=mid+1;  
            else R=mid-1;  
         }  
        if (num++)puts("");  
        if (L-1==0)puts("?");  
        else
         {  
            for (int i=1;i<=pos[0];i++)
             {  
                for (int j=pos[i];j<pos[i]+L-1;j++)printf("%c",s[j]);  
                puts("");  
             }  
         }  
     }  
    return 0;  
}  

 

posted on 2018-03-07 17:35  宣毅鸣  阅读(149)  评论(0编辑  收藏  举报