SPOJ 1812 Longest Common Substring II 后缀自动机求多字符串最长公共子串
2017-07-25 19:01
597 查看
题意:
给若干字符串,求它们的最长公共子串的长度。题解:后缀自动机。
对第一个串建立SAM,并拓扑排序。用后面的串分别匹配。
对于SAM,每个节点新增两个值ml,ans;
ml代表该节点满足单一字符串时的最大值,匹配完一个字符串后重置为0;
ans代表该节点满足所有字符串的最大值,初始化为该状态建立时的代表的子串的长度的最大值(max),每次匹配后更新为min(ans,ml)。
注意每次匹配完字符串,按照拓扑排序从后往前更新(保证父节点在子节点后被更新)用子节点的ml更新父节点的ml,证明如下:
根据后缀自动机上min[i]=max[fa[i]]+1,子节点能匹配的长度ml比父节点的max更长,但父节点是子节点的后缀,父节点也能匹配子节点匹配的子串的后max位,但实际在自动机上该匹配子串并没有转移到父节点过,其ml=0,或其ml比此次能匹配的max小,所以一旦子节点的ml不为0,父节点的ml定可修改为父节点的max值。
最后求所有节点ans的最大值即可。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cmath> using namespace std; const int N=200005; int ans; char s ; struct sam { int cnt,last; int to [26],fa ,mx ,ml ,ans ; int c ,q ; sam() { last=++cnt; } void extend(int c) { int p=last,np=last=++cnt; mx[np]=mx[p]+1;ans[np]=mx[np]; while(p&&!to[p][c])to[p][c]=np,p=fa[p]; if(!p)fa[np]=1; else { int q=to[p][c]; if(mx[q]==mx[p]+1)fa[np]=q; else { int nq=++cnt; mx[nq]=mx[p]+1;ans[nq]=mx[nq]; memcpy(to[nq],to[q],sizeof(to[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; while(to[p][c]==q)to[p][c]=nq,p=fa[p]; } } } void build() { scanf("%s",s+1); int n=strlen(s+1); for(int i=1;i<=n;i++) extend(s[i]-'a'); for(int i=1;i<=cnt;i++)c[mx[i]]++; for(int i=1;i<=n;i++)c[i]+=c[i-1]; for(int i=cnt;i>=1;i--)q[c[mx[i]]--]=i; } void update() { int n=strlen(s+1); int nowlen=0,p=1; for(int i=1;i<=n;i++) { int c=s[i]-'a'; if(to[p][c]) nowlen++,p=to[p][c]; else { while(p&&!to[p][c])p=fa[p]; if(p)nowlen=mx[p]+1,p=to[p][c]; else nowlen=0,p=1; } ml[p]=max(ml[p],nowlen); } for(int i=cnt;i>=1;i--) { int p=q[i]; ans[p]=min(ans[p],ml[p]); if(fa[p]&&ml[p])ml[fa[p]]=mx[fa[p]]; ml[p]=0; } } }sam; int main() { //freopen("lx.in","r",stdin); sam.build(); while(scanf("%s",s+1)!=EOF) sam.update(); for(int i=1;i<=sam.cnt;i++) ans=max(ans,sam.ans[i]); cout<<ans; return 0; }
相关文章推荐
- SPOJ 题目1812 LCS2 - Longest Common Substring II(后缀自动机求多个串的最长公共子串)
- [后缀自动机 模板题] SPOJ 1812 Longest Common Substring II & BZOJ 2946 [Poi2000]公共串
- SPOJ 题目1811 LCS - Longest Common Substring(后缀自动机求最长公共子串)
- SPOJ 1811 Longest Common Substring (后缀自动机第一题,求两个串的最长公共子串)
- SPOJ 1812 Longest Common Substring II(后缀自动机)
- hdu1403---Longest Common Substring(后缀数组求2个字符串的最长公共子串)
- spoj1812-Longest Common Substring II(后缀自动机)
- SPOJ 1812. Longest Common Substring II(后缀自动机)
- spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)
- [SPOJ1812]LCS2 - Longest Common Substring II(后缀自动机)
- SPOJ LCS - Longest Common Substring (2串公共子串, 后缀自动机)
- spoj 1812 Longest Common Substring II(后缀自动机)
- SPOJ 1812 Longest Common Substring II(后缀自动机)
- SPOJ 1812 Longest Common Substring II(后缀自动机)(LCS2)
- SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机)
- [SPOJ1812]LCS2 - Longest Common Substring II-后缀自动机
- 【SPOJ】1812. Longest Common Substring II(后缀自动机)
- [spoj1812]Longest Common Substring II && 后缀自动机
- POJ 2774 Long Long Message+Hdu 1403 Longest Common Substring (后缀数组 最长公共子串)
- spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)