UvaL4513-Stammering Aliens | LCP最长公共前缀+Hash

UvaL4513 - Stammering Aliens

题意:

给出n( n <= 100)个字符串, 只包含小写字母, 每个字符串长度不超过1000且不为空
求出最长的子串,满足在n个字符串当中出现在一半以上的字符串上, 如果有多个这样的子串,按字典序输出

题解:

先吐槽一波,好气哦,cmp函数+l写成了+1(follow me: yi),然后就找了一个小时的bug
这个题是要求构造一个串,跟一半的串有最长公共前缀,所以就将所有的串连起来当作母串处理
然后求出最长公共前缀,因为是要求字典序,所以求后缀数组
hight[]数组的含义就是i与i-1串的最长公共前缀的长度,如果hight[i]>=mid,那么就符合
二分搜索长度,然后判断是否符合条件
sa[]数组的含义是 第i大的串在原串中的起始位置为sa[i]
belong[]数组的含义是 第i个字符属于原串的第几组字符
vis[]数组用于判断是否已经加进记录数组pos[mid]

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>

using namespace std;

const int maxn=110000;
int s[maxn],r[maxn],sa[maxn];
int t1[maxn],t2[maxn],c[maxn];
int Rank[maxn],height[maxn],belong[maxn];
int n,len;

vector<int> pos[1005];
bool vis[110];

bool cmp(int r[],int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}

void da(int str[],int sa[],int n,int m)
{
//    n++;
    int i,j,p,*x=t1,*y=t2;
    for(i=0; i<m; ++i) c[i]=0;
    for(i=0; i<n; ++i) c[x[i]=str[i]]++;
    for(i=0; 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<<=1)
    {
        p=0;
        for(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=1; i<m; ++i) c[i]=0;
        for(i=0; i<n; ++i) c[x[y[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);
        p=1;
        x[sa[0]]=0;
        for(i=1; i<n; ++i)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        if(p>=n) break;
        m=p;
    }
    int k=0;
    n--;
    for(i=0; i<=n; ++i) Rank[sa[i]]=i;
    for(i=0; i<n; ++i)
    {
        if(k) --k;
        j=sa[Rank[i]-1];
        while(str[i+k]==str[j+k]) ++k;
        height[Rank[i]]=k;
    }
}


bool solve(int mid)
{
    bool lp=false,fg=false;
    memset(vis,false,sizeof(vis));
    int cnt=0;
    for(int i=1;i<len;++i)
    {
        if(height[i]<mid)
        {
            memset(vis,false,sizeof(vis));
            vis[belong[sa[i]]]=true;
            cnt=1;
            fg=false;
        }
        else
        {
            if(!vis[belong[sa[i]]])
            {
                cnt++;
                vis[belong[sa[i]]]=true;
            }
            if(cnt>(n/2))
            {
                lp=true;
                if(!fg)
                {
                    pos[mid].push_back(sa[i]);
                    fg=true;
                }
            }
        }
    }
    return lp;
}

int main()
{
    char ss[1005];
    bool fg=false;
    while(scanf("%d",&n)&&n)
    {
        if(fg) puts("");
        len=0;
        for(int i=0; i<n; ++i)
        {
            scanf("%s",ss);
            int d=strlen(ss);
            for(int j=0;j<d;++j)
            {
                s[len]=ss[j]-'a'+1;
                belong[len]=i;
                len++;
            }
            s[len++]=27+i;
        }
        s[len-1]=0;
        da(s,sa,len,130);

        for(int i=0;i<=1000;++i) pos[i].clear();

        int l=0,r=1000,mid,ans=0;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(solve(mid))
            {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }

        if(ans==0)
        {
            puts("?");
            continue;
        }
/*
        printf("---%d\n",ans);
        for(int i=0;i<pos[ans].size();++i)
            printf("%d ",pos[ans][i]);
        printf("\n");
*/


        for(int i=0;i<pos[ans].size();++i)
        {
            for(int j=0;j<ans;++j)
                printf("%c",s[pos[ans][i]+j]+'a'-1);
            printf("\n");
        }
        fg=true;
    }

    return 0;
}



猜你喜欢

转载自blog.csdn.net/exchan/article/details/78339766