1. 程式人生 > >POJ2774 Long Long Message

POJ2774 Long Long Message

蒟蒻的第一道字尾陣列的題目!!

SA是個好東西,本題就是考察它的經典應用——求一個字串裡面兩個字尾的最長公共字首!

所以我們就可以考慮把兩個字串拼起來,然後查詢兩個字尾,使得他們的最長公共字首最長。

然後就是板子了吧qwqwq(感覺SA的寫法和網上很多人的不一樣??不過原理還是一樣的啦qwq)

不會SA的可以參考自為風月馬前卒大佬的blog,講的真的很詳細:戳我

需要注意的一點就是最後查詢的時候一定要保證兩個字尾的起始位置下標不能在同一個子串裡,怎麼處理呢?一個簡單的方法是構建字串的時候就在兩個字串中間加入一個根本就不會出現的字元。

程式碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 300010
using namespace std;
int len1,len2,n,ans,m;
int tag[MAXN],h[MAXN],tax[MAXN],s[MAXN],rnk[MAXN],tp[MAXN],sa[MAXN];
char s1[MAXN],s2[MAXN];
inline void qsort()
{
    for(int i=1;i<=m;i++) tax[i]=0;
    for(int i=1;i<=n;i++) tax[rnk[i]]++;
    for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
    for(int i=n;i>=1;i--) sa[tax[rnk[tp[i]]]--]=tp[i];
}
inline void suffixsort()
{
    m=75;
    for(int i=1;i<=n;i++) rnk[i]=s[i],tp[i]=i;
    qsort();
    for(int w=1,p=0;p<n;m=p,w<<=1)
    {
        p=0;
        for(int i=1;i<=w;i++) tp[++p]=n-w+i;
        for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
        qsort();
        swap(tp,rnk);
        rnk[sa[1]]=p=1;
        for(int i=2;i<=n;i++) rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]])&&(tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
    }
}
inline void get_h()
{
    int hi=0,j;
    for(int i=1;i<=n;i++)
    {
        j=sa[rnk[i]-1];
        if(hi>0) hi--;
        for(;j+hi<=n&&i+hi<=n;hi++)
            if(s[i+hi]!=s[j+hi]) break;
        h[rnk[i]-1]=hi;
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%s",s1+1),scanf("%s",s2+1);
    len1=strlen(s1+1),len2=strlen(s2+1);
    n=len1+len2+1;
    for(int i=1;i<=len1;i++) s[i]=s1[i]-'a'+1;
    s[len1+1]=30;
    for(int i=1;i<=len2;i++) s[i+len1+1]=s2[i]-'a'+1;
    suffixsort();
    get_h();
    for(int i=1;i<n;i++) 
        if((sa[i]<=len1)!=(sa[i+1]<=len1))
            ans=max(ans,h[i]);
    printf("%d\n",ans);
    return 0;
}