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