【POJ】2774 Long Long Message

【题意】给定两个字符串S和T,求最长公共子串。len<=10^5。

【算法】后缀自动机

【题解】对字符串S建SAM,然后令串T在S上跑匹配。

这是自动机最原本的功能——匹配,就是串T在SAM(S)上走,不能匹配就沿失配边走,这样得到的是T上以每个字符结尾的子串中与S的最长公共子串,取Max即是答案。

注意失配不要走到0节点处。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct tree{int len,fa,t[30];}t[maxn*2];
int last,n,m,tot;
char s[maxn],T[maxn];
void insert(int c){
    int np=++tot;
    t[np].len=t[last].len+1;
    int x=last;
    while(x&&!t[x].t[c])t[x].t[c]=np,x=t[x].fa;
    last=np;
    if(!x)t[np].fa=1;else{
        int y=t[x].t[c];
        if(t[y].len==t[x].len+1)t[np].fa=y;else{
            int nq=++tot;
            t[nq]=t[y];
            t[nq].len=t[x].len+1;
            t[nq].fa=t[y].fa;t[np].fa=t[y].fa=nq;
            while(x&&t[x].t[c]==y)t[x].t[c]=nq,x=t[x].fa;
        }
    }
}
int main(){
    scanf("%s",T+1);m=strlen(T+1);
    last=tot=1;
    for(int i=1;i<=m;i++)insert(T[i]-'a');
    scanf("%s",s+1);n=strlen(s+1);
    int ans=0,cnt=0,now=1;
    for(int i=1;i<=n;i++){
        while(now!=1&&!t[now].t[s[i]-'a'])now=t[now].fa,cnt=t[now].len;
        if(t[now].t[s[i]-'a'])cnt++,now=t[now].t[s[i]-'a'];else cnt=0;
        ans=max(ans,cnt);
    }
    printf("%d",ans);
    return 0;
}
View Code

 

posted @ 2017-12-26 16:42  ONION_CYC  阅读(146)  评论(0编辑  收藏  举报