LCS&LCS2 SAM SPOJ
Posted nishikino-curtis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCS&LCS2 SAM SPOJ相关的知识,希望对你有一定的参考价值。
LCS - Longest Common Substring
Description
给两个长度(le 250000)的小写字母串, 求最长公共子串.
Solution
子串就是SAM了. 对其中一个建出SAM, 另一个在上面跑, 如果可以转移, 就直接转移, 长度加一, 否则跳父亲到可以转移, 自然是取(max_{alpha})了.
如果都不行就回到根.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;
const int maxn = 700005;
int ans;
char s1[maxn], s2[maxn];
struct SuffixAutoMation
{
int tr[maxn][26], fa[maxn], mx[maxn];
int lst, cnt;
SuffixAutoMation() {
lst = cnt = 1;
}
void Insert(int c) {
int p = lst, np = ++cnt;
lst = np; mx[np] = mx[p] + 1;
for (; p && !tr[p][c]; p = fa[p]) tr[p][c] = np;
if (!p) fa[np] = 1;
else {
int q = tr[p][c];
if (mx[p] + 1 == mx[q]) fa[np] = q;
else {
int nq = ++cnt;
mx[nq] = mx[p] + 1;
for (int i = 0; i < 26; ++i) tr[nq][i] = tr[q][i];
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for (; tr[p][c] == q; p = fa[p]) tr[p][c] = nq;
}
}
//siz[np] = 1;
}
void Build(int n) {
for (int i = 1; i <= n; ++i)
Insert(s1[i] - 'a');
}
void Solve(int n) {
int pos = 1, len = 0;
for (int i = 1; i <= n; ++i) {
int ch = s2[i] - 'a';
if (tr[pos][ch]) len++, pos = tr[pos][ch];
else {
for (; pos && !tr[pos][ch]; ) pos = fa[pos];
if (pos) len = mx[pos] + 1, pos = tr[pos][ch];
else pos = 1, len = 0;
}
ans = max(ans, len);
}
}
}SAM;
int main() {
scanf("%s%s", s1 + 1, s2 + 1);
int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
SAM.Build(l1);
SAM.Solve(l2);
printf("%d
", ans);
return 0;
}
LCS2 - Longest Common Substring
Description
还是小写字符串((le 100000)), 不过增加到了(10)个.
Solution
建一个SAM, 其他的分别在上面跑, 求出(ans_{alpha}{2, 3, 4, ldots,n}), 和(max_{alpha})取个min.
注意实现细节.
由于跑了很多串, 可能出现匹配位置不同的情况, 注意parent树节点的儿子的答案可以拿来取max. 用(max)的拓扑性就好了.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>
using namespace std;
const int maxn = 3e+5 + 5;
int n, ans;
int a[maxn], b[maxn];
char s[maxn];
struct SuffixAutoMation
{
int tr[maxn][26], mx[maxn], sz[maxn], fa[maxn];
int lst, cnt;
int mxv[maxn], mnv[maxn];
SuffixAutoMation() {
lst = cnt = 1;
}
void Insert(int c) {
int p = lst, np = ++cnt;
lst = np; mx[np] = mx[p] + 1;
for (; p && !tr[p][c]; p = fa[p]) tr[p][c] = np;
if (!p) fa[np] = 1;
else {
int q = tr[p][c];
if (mx[p] + 1 == mx[q]) fa[np] = q;
else {
int nq = ++cnt;
mx[nq] = mx[p] + 1;
for (int i = 0; i < 26; ++i) tr[nq][i] = tr[q][i];
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for (; tr[p][c] == q; p = fa[p]) tr[p][c] = nq;
}
}
sz[np] = 1;
}
void RadixSort() {
memset(b, 0, sizeof b);
for (int i = 1; i <= cnt; ++i) b[mx[i]]++;
for (int i = 1; i <= cnt; ++i) b[i] += b[i - 1];
for (int i = 1; i <= cnt; ++i) a[b[mx[i]]--] = i;
}
void Build(int n) {
for (int i = 1; i <= n; ++i) Insert(s[i] - 'a');
memset(mnv, 0x3f, sizeof mnv);
}
void Work(int n) {
int p = 1, len = 0;
//memset(mxv, 0, sizeof mxv);
for (int i = 1; i <= n; ++i) {
int ch = s[i] - 'a';
if (tr[p][ch]) p = tr[p][ch], len++, mxv[p] = max(mxv[p], len);
else {
for (; p && !tr[p][ch]; ) p = fa[p];
if (p) len = mx[p] + 1, p = tr[p][ch], mxv[p] = max(mxv[p], len);
else p = 1, len = 0;
}
}
for (int i = cnt; i; --i) {
int x = a[i], f = fa[x];
mxv[f] = max(mxv[f], min(mxv[x], mx[f]));
mnv[x] = min(mnv[x], mxv[x]);
mxv[x] = 0;
}
}
void CheckAns() {
for (int i = 1; i <= cnt; ++i) ans = max(ans, mnv[i]);
}
}SAM;
int main() {
scanf("%s", s + 1);
//memset(mnv, 0x3f, sizeof mnv);
int l = strlen(s + 1);
SAM.Build(l);
SAM.RadixSort();
while (scanf("%s", s + 1) != EOF) {
l = strlen(s + 1);
//if (!l) break;
++n;
SAM.Work(l);
}
SAM.CheckAns();
printf("%d
", ans);
return 0;
}
以上是关于LCS&LCS2 SAM SPOJ的主要内容,如果未能解决你的问题,请参考以下文章
spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring