poj3294 Life Forms

题目大意:给n个字符串,求最大长度的字符串,使其在一半以上的字符串中出现过,按字典序输出

后缀数组。。。二分最大长度,再按sa数组的顺序记录不同最长字符串出现的位置。

代码:

 

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<set>
#include<vector>
using namespace std;
const int N=2e5;
char t[N];
int s[N],sa[N],r[N],h[N],c[N],x[N],y[N],be[N],len,vis[N];
set<int>se;
vector<int>g;
void build(int n,int m){
     int i,j,k;
     for(i=0;i<m;i++) c[i]=0;
     for(i=0;i<n;i++){
         x[i]=s[i];
         c[x[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(j=1;j<n;j*=2){
         k=0;
         for(i=n-j;i<n;i++) y[k++]=i;
         for(i=0;i<n;i++) if(sa[i]>=j) y[k++]=sa[i]-j;
         for(i=0;i<m;i++) c[i]=0;
         for(i=0;i<n;i++) c[x[i]]++;
         for(i=1;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);
         m=0;
         x[sa[0]]=m++;
         for(i=1;i<n;i++){
            if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=m-1;
            else x[sa[i]]=m++;
         }
         if(m==n) break;
     }
     for(i=0;i<n;i++) r[sa[i]]=i;

     k=0;
     for(i=0;i<n-1;i++){
        if(k) k--;
        j=sa[r[i]-1];
        while(s[i+k]==s[j+k]) k++;
        h[r[i]]=k;
     }
     //for(i=0;i<n;i++) printf("%d\n",h[i]);
}
int f(int x,int k){
    int i,l,r,sum=0,j;
    l=r=-1;
    memset(vis,0,sizeof(vis));        //vis数组判断在那个字符串中出现过
    for(i=1;i<len;i++){
        if(h[i]>=x){
            if(h[i-1]<x) l=i;
            r=i;
            if(vis[be[sa[i]]]==0) sum++;
            vis[be[sa[i]]]=1;
            if(vis[be[sa[i-1]]]==0) sum++;
            vis[be[sa[i-1]]]=1;
        }
        else{
            if(sum>k) return 1;
            if(r!=-1) for(j=l;j<=r;j++)  vis[be[sa[j]]]=vis[be[sa[j-1]]]=0;    //最长公共前缀小于二分的长度x,重新记录
            l=r=-1;
            sum=0;
        }
    }
    return 0;
}

void find(int x,int k){
    g.clear();
    memset(vis,0,sizeof(vis));
    int i,pos,j,l=-1,r=-1,sum=0;;
    for(i=1;i<len;i++){
        if(h[i]>=x){
            if(h[i-1]<x) l=i;
            r=i;
            pos=sa[i];
            if(vis[be[sa[i]]]==0) sum++;
            vis[be[sa[i]]]=1;

            if(vis[be[sa[i-1]]]==0) sum++;
            vis[be[sa[i-1]]]=1;
        }
        else{
            if(sum>k) g.push_back(pos);
            if(r!=-1) for(j=l;j<=r;j++)  vis[be[sa[j]]]=vis[be[sa[j-1]]]=0;
            l=r=-1;
            sum=0;
        }
    }
}
int main(){
    int i,n,j,m;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        if(n==1){
            scanf("%s",t);
            printf("%s\n\n",t);
            continue;
        }
        len=0;
        memset(be,0,sizeof(be));
        for(i=1;i<=n;i++){
            scanf("%s",t);
            m=strlen(t);
            for(j=0;j<m;j++){
                be[len]=i;
                s[len++]=t[j];
            }
            s[len++]=1000+i;
        }
        s[len-1]=0;
        build(len,2000);

        int l=0,r=len,mid;
        while(l+1<r){
            mid=(l+r)/2;
            if(f(mid,n/2)) l=mid;
            else r=mid;
        }

        if(l==0) printf("?\n\n");
        else{
            find(l,n/2);
            for(i=0;i<g.size();i++){
                for(j=g[i];j<g[i]+l;j++) printf("%c",s[j]);
                printf("\n");
            }
            printf("\n");
        }
    }
    return 0;
}

 

上一篇:题解 CF75A 【Life Without Zeros】


下一篇:有哪些文艺到爆炸的句子?