POJ 2774 Long Long Message(最长公共子串)

来源:互联网 发布:linux跳板机搭建 编辑:程序博客网 时间:2024/05/16 12:55

题意:求两个字符串的最长公共子串。

题解:

 首先如果这两个长字符串存在某个最长的公共子串,那么该子串一定分别是这两个串的后缀的前缀.所以我们将两个串中间加一个符号‘$’然后连接起来形成一个新串(还要添尾0).然后我们求这个新串的height数组值,我们从sa[1]到新串长sa[n-1]依次扫描字典序相邻的两个后缀的LCP,如果这两个后缀分别属于之前不同的两个串,那么他们的LCP值就可能是他们最长连续公共子串的长度。否则的话就不是。求出满足条件的最大值。

代码:

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <string>using namespace std;const int MAX=200000+10;int rk[MAX],sa[MAX],ht[MAX];int s[MAX],buc[MAX];int *x=new int[MAX],*y=new int[MAX];void getsa(int n,int m){    int i,k,p;    for(i=0;i<m;i++) buc[i]=0;    for(i=0;i<n;i++) buc[x[i]=s[i]]++;    for(i=1;i<m;i++) buc[i]+=buc[i-1];    for(i=n-1;i>=0;i--) sa[--buc[s[i]]]=i;    for(k=1,p=1;p<n;k<<=1,m=p)    {        p=0;        for(i=n-1;i>=n-k;i--) y[p++]=i;        for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;        for(i=0;i<m;i++) buc[i]=0;        for(i=0;i<n;i++) buc[x[y[i]]]++;        for(i=1;i<m;i++) buc[i]+=buc[i-1];        for(i=n-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i];        swap(x,y);        p=1;x[sa[0]]=0;        for(i=1;i<n;i++)        {            if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=p-1;            else x[sa[i]]=p++;        }    }    return ;}void getlcp(int n){    int i,j,k=0;    for(i=0;i<n;i++) rk[sa[i]]=i;    for(i=0;i<n;ht[rk[i++]]=k)        for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);    return ;}int main(){    string a,b;    cin>>a;    cin>>b;    int len1=a.length();    int len2=b.length();    for(int i=0;i<len1;i++)        s[i]=a[i]-'a'+2;    s[len1]=1;    for(int i=0;i<len2;i++)        s[len1+1+i]=b[i]-'a'+2;    s[len1+len2+1]=0;    int n=len1+len2+2;    getsa(n,30);    getlcp(n);    int ans=0;    for(int i=1;i<n;i++)    {        int sa1=sa[i-1],sa2=sa[i];        if(sa1>sa2) swap(sa1,sa2);        if(0<=sa1&&sa1<len1&&len1<sa2&&sa2<=len1+len2)            ans=max(ans,ht[i]);    }    printf("%d\n",ans);    return 0;}


0 0
原创粉丝点击