poj3294 Life Forms

【题意】

求出现次数超过一半的最长子串

【分析】

把所有的串连在一起,中间放上间隔符,然后求height之后

二分答案转换为判定问题,每次按height分组,看一组中是否出现了超过一半次数即可

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,len[105];
char s[1005];
const int maxn=100*1005;
int a[maxn],siz;
int cnt[maxn],fz[maxn],oldrk[maxn],sa[maxn],id[maxn],rk[maxn],h[maxn],pos[maxn];
bool cmp(int x,int y,int w)
{
    return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w];
}
void calcsa()
{
    int m=350;
    for(int i=0;i<=m;i++) cnt[i]=0;
    for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++;
    for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
    int i,j,p=m;
    for(int w=1;;w<<=1,m=p)    
    {
        for(p=0,i=n;i>n-w;i--) id[++p]=i;
        for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
        for(i=0;i<=m;i++) cnt[i]=0;
        for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++;
        for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i];
        for(i=1;i<=n;i++) oldrk[i]=rk[i];
        for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p;
        if(p==n)
        {
            for(i=1;i<=n;i++) sa[rk[i]]=i;
            break;
        }
    }
}
void calch()
{
    int i,k=0;
    for(i=1;i<=n;i++)
    {
        if(k) k--;
        while(a[i+k]==a[sa[rk[i]-1]+k]) k++;
        h[rk[i]]=k;
    }
}
bool check(int x)
{
    int cntt=0,tot=0,vis[104];
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        if(h[i]>=x)
        {
            for(int j=1;j<=siz;j++)
            {
                if(sa[i]>len[j-1] && sa[i]<=len[j]) cntt+=vis[j]?0:1,vis[j]=1;
                if(sa[i-1]>len[j-1] && sa[i-1]<=len[j]) cntt+=vis[j]?0:1,vis[j]=1;
            }
        }
        else
        {
            if(cntt>siz/2)
                pos[++tot]=sa[i-1];
            cntt=0;
            memset(vis,0,sizeof(vis));
        }
    }
    if(cntt>siz/2) pos[++tot]=sa[n];
    if(tot)
    {
        pos[0]=tot;
        return 1;
    }
    return 0;
} 
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int round=0;
    while(scanf("%d",&n)!=EOF && n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            int l=strlen(s);
            len[i]=len[i-1]+1;
            for(int j=0;j<l;j++) a[len[i]+j]=s[j]-'a'+1;
            len[i]+=l-1;
            if(i!=n) len[i]++,a[len[i]]=26+i;
        }
        siz=n;
        n=len[n];
        calcsa();
        calch();
        int l=0,r=n;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid)) l=mid+1;
            else r=mid-1;
        }
        if(round) printf("\n");
        if(l==1)
        {
            printf("?\n");
            continue;
        }
        for(int i=1;i<=pos[0];i++)
        {
            for(int j=pos[i];j<pos[i]+l-1;j++)
                printf("%c",a[j]+'a'-1);
            printf("\n");
        }
        round++;
    }
    return 0;
}

 

posted @ 2021-04-27 19:22  andyc_03  阅读(50)  评论(0)    收藏  举报