[POI2000] 最长公共子串

来源:互联网 发布:wifi满信号网络特别慢 编辑:程序博客网 时间:2024/05/17 11:07

给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

任务

  • 从文件中读入单词
  • 计算最长公共子串的长度
  • 输出结果到文件

输入

文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

输出:

仅一行,一个整数,最长公共子串的长度。

样例输入:

3abcbbcaacbc

样例输出:

2


把字符串连在一起后缀数组预处理,然后二分答案,检验:将height<答案的字符串另开一段,最后判断总段数是否等于字符串总数即可

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=50000+100;
char s[maxn];
int sa[maxn]={0},t[maxn]={0},t2[maxn]={0},c[maxn]={0};
int d[maxn]={0},M;
inline int idx(char c){
    return c-'A';
}
inline void build_sa(int n,int m){
    int *x=t,*y=t2;
    for(int i=0;i<m;i++)
        c[i]=0;
    for(int i=0;i<n;i++)
        c[x[i]=d[i]]++;
    for(int i=1;i<m;i++)
        c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--)
        sa[--c[x[i]]]=i;
    for(int k=1;k<n;k<<=1){
        int p=0;
        for(int i=n-k;i<n;i++)
            y[p++]=i;
        for(int i=0;i<n;i++)
            if(sa[i]>=k)
                y[p++]=sa[i]-k;
        for(int i=0;i<m;i++)
            c[i]=0;
        for(int i=0;i<n;i++)
            c[x[y[i]]]++;
        for(int i=1;i<m;i++)
            c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--)
            sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1;i<n;i++){
            x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])?p-1:p++;
        }
        if(p>=n)
            break;
        m=p;
    }
}
int belong[maxn];
int rank[maxn],height[maxn];
inline void getheight(int n){
    int h=0;
    for(int i=0;i<n;i++)
        rank[sa[i]]=i;
    for(int i=0;i<n;i++){
        if(rank[i]==0) h=0;
        else{
            int k=sa[rank[i]-1];
            if(--h<0)
                h=0;
            while(d[i+h]==d[k+h])
                h++;
        }
        height[rank[i]]=h;
    }
}
int ba[maxn],n;
bool check(int x){
    for(int i=1;i<=n;i++){
        if(height[i]>=x){
            int j=i;
            while(height[j]>=x&&j<=n)
                j++;
            j--;
            memset(ba,0,sizeof(ba));
            for(int k=i-1;k<=j;k++)
                ba[belong[sa[k]]]=true;
            int k=1;
            while(ba[k]&&k<=M)
                k++;
            if(k==M+1)
                return true;
            i=j;
        }
    }
    return false;
}
int main(){
    freopen("pow.in","r",stdin);
    freopen("pow.out","w",stdout);
    scanf("%d",&M);
    n=0;
    for(int i=1;i<=M;i++){
        scanf("%s",s);
        for(char *p=s;*p;p++){
            d[++n]=*p-'a';
            belong[n]=i;
        }
        if(i<M)
            d[++n]=30+i;
    }
    build_sa(n,100);
    getheight(n);
    int ans=0;
    int l=0,r=n;
    while(l+1!=r){
        int mid=(l+r)>>1;
        if(check(mid))
            l=mid;
        else r=mid;
    }
    if(check(r))
        ans=r;
    else ans=l;
    printf("%lld\n",ans);
return 0;
}

0 0
原创粉丝点击