SPOJ - LCS2 (后缀自动机)
作者:互联网
题意
给若干个串,求这些串最长公共子串的长度。
思路
后缀自动机求lcs模版题。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
struct Pam {
int len[maxn], link[maxn];
int nxt[maxn][26];
int last, tot;
int mx[maxn], mi[maxn];
void init() {
len[0] = link[0] = 0;
last = tot = 1;
}
void extend(int c) {
c -= 'a';
int cur = ++tot, p = last;
len[cur] = len[last] + 1;
for (; p && !nxt[p][c]; p = link[p]) nxt[p][c] = cur;
if(!p) {
link[cur] = 1;
} else {
int q = nxt[p][c];
if(len[q] == len[p]+1) {
link[cur] = q;
} else {
int clone = ++tot;
len[clone] = len[p] + 1;
memcpy(nxt[clone], nxt[q], sizeof(nxt[q]));
link[clone] = link[q];
for (; p && nxt[p][c] == q; p = link[p]) nxt[p][c] = clone;
link[q] = link[cur] = clone;
}
}
last = cur;
}
int c[maxn], a[maxn];
void topo(int n) {
for (int i = 1; i <= tot; ++i) c[i] = 0;
for (int i = 1; i <= tot; ++i) ++c[len[i]];
for (int i = 1; i <= tot; ++i) c[i] += c[i-1];
for (int i = 1; i <= tot; ++i) a[c[len[i]]--] = i;
for (int i = 1; i <= tot; ++i) mi[i] = len[i];
}
void solve(const string &s) {
int p = 1, cnt = 0, ans = 0;
for (int i = 1; i <= tot; ++i) mx[i] = 0;
for (int i = 0; s[i]; ++i) {
int c = s[i] - 'a';
if(nxt[p][c]) {
++cnt;
p = nxt[p][c];
} else {
for (; p && !nxt[p][c]; p = link[p]);
if(!p) cnt = 0, p = 1;
else cnt = len[p]+1, p = nxt[p][c];
}
mx[p] = max(mx[p], cnt);
}
for (int i = tot; i >= 1; --i) mx[link[a[i]]] = max(mx[link[a[i]]], mx[a[i]]);
for (int i = 1; i <= tot; ++i) mi[i] = min(mi[i], mx[i]);
}
void write() {
int ans = 0;
for (int i = 1; i <= tot; ++i) ans = max(ans, mi[i]);
printf("%d\n", ans);
}
}sam;
string str;
int main() {
// freopen("input.in", "r", stdin);
sam.init();
cin >> str;
int n = str.length();
for (int i = 0; str[i]; ++i) sam.extend(str[i]);
sam.topo(n);
while(cin >> str)
sam.solve(str);
sam.write();
return 0;
}
标签:nxt,LCS2,cur,后缀,len,int,SPOJ,link,maxn 来源: https://www.cnblogs.com/acerkoo/p/11706210.html