poj2774 Long Long Message(后缀数组)

http://poj.org/problem?id=2774

 

先做一道小水题提提神

题意:求两个串的最长公共连续子串

可以二分+哈希做

但我要用后缀数组做

两个串拼起来,然后取满足后缀起点分别属于两个串的height数组的最大值

 

一开始没用特殊字符隔开两个串

他AC了,数据有缺陷呐

第二个串因为最后面是字符串的结束,可以保证公共串不会越界第二个串

但第一个串就没保证了,例如 baa和aaa

然后加了特殊字符'#'隔开,它RE了。。。

因为后缀数组的时候,统计前缀和是 字符-'a'+1,统计1—26,‘#’不满足要求

用 'a'+26,统计1——27

 

一不留神就出bug,哎

 

#include<cmath>
#include<cstdio>
#include<cstring> 
#include<algorithm>

using namespace std;

#define N 200005

char ch[N];
int m,n,k,a[N],v[N],p,q,sa[2][N],rk[2][N],h[N];


void mul(int *sa,int *rk,int *SA,int *RK)
{
    for(int i=1;i<=n;i++) v[rk[sa[i]]]=i;
    for(int i=n;i;i--)
        if(sa[i]>k) 
            SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    for(int i=n-k+1;i<=n;i++) 
        SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;i++) 
        RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
}
void presa()
{
    p=0;
    q=1;
    for(int i=1;i<=27;++i) v[i]=0;
    for(int i=1;i<=n;i++) v[a[i]]++;
    for(int i=1;i<=27;i++) v[i]+=v[i-1];
    for(int i=1;i<=n;i++) 
        sa[p][v[a[i]]--]=i;
    for(int i=1;i<=n;i++) 
        rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]);
    for(k=1;k<n;k<<=1,swap(p,q))
        mul(sa[p],rk[p],sa[q],rk[q]);
    for(int i=1,k=0;i<=n;i++)
    {
        int j=sa[p][rk[p][i]-1];
        while(a[i+k]==a[j+k]) k++;
        h[rk[p][i]]=k;if(k) k--;
    }
}

void solve()
{
    int ans=0,t1,t2;
    for(int i=2;i<=n;++i)
    {
        t1=sa[p][i]<=m;
        t2=sa[p][i-1]<=m;
        if(t1+t2==1) ans=max(ans,h[i]);
    }
    printf("%d",ans);
}

int main()
{
    scanf("%s",ch+1);
    m=strlen(ch+1);
    ch[++m]='a'+26;
    scanf("%s",ch+m+1);
    n=strlen(ch+1);
    for(int i=1;i<=n;i++) a[i]=ch[i]-'a'+1;
    presa();
    solve();
}

 

posted @ 2021-08-15 07:56  TRTTG  阅读(25)  评论(0编辑  收藏  举报