SPOJ - LCS Longest Common Substring 后缀自动机
2017-03-04 18:54
357 查看
Longest Common Substring
SPOJ- LCS
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
Source SPOJ - LCS My Solution 题意:求两个字符串的最长公共子串。
后缀自动机
看了很久 WJMZBMR 讲后缀自动机的ppt才大致把后缀自动机搞懂^_^,
此外附上两个比较好的讲后缀自动机的博客 后缀自动机 模版,后缀自动机讲解
这题直接用一个字符串建立后缀自动机,然后用另一个串在自动机上跑即可,操作和AC自动机有点类似,
只是AC自动机匹配失败的时候用的fail指针,而这里用pre树跳转。
复杂度 O(n)
#include <iostream> #include <cstdio> #include <string> #include <cstring> using namespace std; typedef long long LL; const int maxn = 2*2.5e5 + 8; string s; struct SAM{ int ch[maxn][26], pre[maxn], val[maxn]; int last, tot; void init(){ last = tot = 0; memset(ch[0], -1, sizeof ch[0]); pre[0] = -1; val[0] = 0; } void extend(int c){ int p = last, np = ++tot; val[np] = val[p] + 1; memset(ch[np], -1, sizeof ch[np]); while(~p && ch[p][c] == -1) ch[p][c] = np, p = pre[p]; if(p == -1) pre[np] = 0; else{ int q = ch[p][c]; if(val[q] != val[p] + 1){ int nq = ++tot; memcpy(ch[nq], ch[q], sizeof ch[q]); val[nq] = val[p] + 1; pre[nq] = pre[q]; pre[q] = pre[np] = nq; while(~p && ch[p][c] == q) ch[p][c] = nq, p = pre[p]; } else pre[np] = q; } last = np; } int _find(const string &s){ int sz = s.size(), u = 0, tmp = 0, c, i, res = 0; for(i = 0; i < sz; i++){ c = s[i] - 'a'; if(~ch[u][c]) tmp++, u = ch[u][c]; else{ while(~u && ch[u][c] == -1) u = pre[u]; if(~u) tmp = val[u] + 1, u = ch[u][c]; else tmp = 0, u = 0; } res = max(res, tmp); } return res; } } sam; int main() { #ifdef LOCAL freopen("11.in", "r", stdin); //freopen("11.out", "w", stdout); int T = 2; while(T--){ #endif // LOCAL ios::sync_with_stdio(false); cin.tie(0); int n, i; cin >> s; n = s.size(); sam.init(); for(i = 0; i < n; i++) sam.extend(s[i] - 'a'); cin >> s; cout << sam._find(s) << endl;; #ifdef LOCAL cout << endl; } #endif // LOCAL return 0; }
Thank you!
------from ProLights
相关文章推荐
- [SPOJ]1812 LCS2 后缀自动机
- SPOJ LCS(Longest Common Substring-后缀自动机-结点的Parent包含关系)
- SPOJ LCS2 后缀自动机
- SPOJ 1811. Longest Common Substring (LCS,两个字符串的最长公共子串, 后缀自动机SAM)
- SPOJ 题目1811 LCS - Longest Common Substring(后缀自动机求最长公共子串)
- spoj/LCS 1811 小小后缀自动机
- SPOJ LCS Longest Common Substring 后缀自动机
- 【后缀自动机】SPOJ(LCS)[Longest Common Substring]题解
- SPOJ 1811 LCS(后缀自动机)
- 【再谈后缀自动机(入门)】[SPOJLCS2]Longest Common Substring II
- [SPOJ1811]LCS - Longest Common Substring(后缀自动机)
- SPOJ 题目1812 LCS2 - Longest Common Substring II(后缀自动机求多个串的最长公共子串)
- 【后缀自动机】[SPOJLCS]Longest Common Substring
- 后缀自动机(SAM) :SPOJ LCS - Longest Common Substring
- 【后缀自动机】[SPOJ LCS]Longest Common Substring
- SPOJ 1811 LCS 后缀自动机
- [SPOJ1812]LCS2 - Longest Common Substring II(后缀自动机)
- SPOJ 1811 LCS [后缀自动机]
- SPOJ LCS(Longest Common Substring-后缀自动机-结点的Parent包含关系)
- 【后缀自动机】[SPOJ LCS2]Longest Common Substring II