SPOJ - LCS 后缀自动机入门

Posted Meek

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ - LCS 后缀自动机入门相关的知识,希望对你有一定的参考价值。

LCS - Longest Common Substring

 

A string is finite sequence of characters over a non-empty finite set Σ.

In this problem, Σ is the set of lowercase letters.

Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.

Now your task is simple, for two given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

Input

The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.

Output

The length of the longest common substring. If such string doesn‘t exist, print "0" instead.

Example

Input:
alsdfkjfjkdsal
fdjskalajfkdsla

Output:
3

Notice: new testcases added

 


题意:

  求两个串的最长公共子串。

题解:

  先用第一个串构造出后缀自动机,然后逐个的匹配第二个串

  如果当前节点失配,利用Suffix Links 往后跳就可以了。

#include <bits/stdc++.h>
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}return x*f;}
using namespace std;

const int N = 3e5+7;

const long long mod = 1000000007;

int isPlus[N * 2],endpos[N * 2];int d[N * 2];
int tot,slink[2*N],trans[2*N][28],minlen[2*N],maxlen[2*N],pre;
int newstate(int _maxlen,int _minlen,int* _trans,int _slink){
    maxlen[++tot]=_maxlen;minlen[tot]=_minlen;
    slink[tot]=_slink;
    if(_trans)for(int i=0;i<26;i++)trans[tot][i]=_trans[i],d[_trans[i]]+=1;
    return tot;
}
int add_char(char ch,int u){
    int c=ch-a,v=u;
    int z=newstate(maxlen[u]+1,-1,NULL,0);
    isPlus[z] = 1;
    while(v&&!trans[v][c]){trans[v][c]=z;d[z]+=1;v=slink[v];}
    if(!v){ minlen[z]=1;slink[z]=1;return z;}
    int x=trans[v][c];
    if(maxlen[v]+1==maxlen[x]){slink[z]=x;minlen[z]=maxlen[x]+1;return z;}
    int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]);
    slink[z]=slink[x]=y;minlen[x]=minlen[z]=maxlen[y]+1;
    while(v&&trans[v][c]==x){trans[v][c]=y;d[x]--,d[y]++;v=slink[v];}
    minlen[y]=maxlen[slink[y]]+1;
    return z;
}
void init_sam() {
    for(int i = 1; i <= tot; ++i)
        for(int j = 0; j < 26; ++j) trans[i][j] = 0;
    pre = tot = 1;
}
char a[N],b[N];
int main() {
    scanf("%s%s",a,b);
    init_sam();
    int n = strlen(a);
    int m = strlen(b);
    for(int i = 0; i < n; ++i)
        pre = add_char(a[i],pre);
    int ans = 0;
    int now = 1;
    int sum = 0;
    for(int i = 0; i < m; ++i) {
        if(trans[now][b[i]-a]) {
            now = trans[now][b[i]-a];
        } else {
            while(now) {
                now = slink[now];
                if(trans[now][b[i]-a]) break;
            }
            if(!now) now = 1,sum = 0;
            else {
                if(trans[now][b[i]-a]) {
                    sum = maxlen[now] + 1;
                    now = trans[now][b[i]-a];
                }
            }
        }
        ans = max(ans,sum);
    }
    printf("%d\n",ans);
}

 

以上是关于SPOJ - LCS 后缀自动机入门的主要内容,如果未能解决你的问题,请参考以下文章

后缀自动机(SAM) :SPOJ LCS - Longest Common Substring

SPOJ LCS2 - Longest Common Substring II 后缀自动机 多个串的LCS

SPOJ 1812 LCS2 后缀自动机

SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机)两种做法

SPOJ-LCS 后缀自动机

并不对劲的[spoj1812]LCS2