Description
求若干个串的最长的公共子串的长度。
Solution
考虑将这若干个串全部拼起来,中间用一些不在字符集内的符号隔开。
然后二分答案 \(K\),如果连续的一段 \(height\) 都大于等于 \(K\),且每个串都出现了至少一次,则是可行的。
Code
#include <bits/stdc++.h> using namespace std; const int _ = 1e5 + 10; int N, n, s[_], belong[_]; int rnk[_], sa[_], height[_]; char str[_]; void SA() { static int t[_], a[_], buc[_], fir[_], sec[_], tmp[_]; copy(s + 1, s + N + 1, t + 1); sort(t + 1, t + N + 1); int *end = unique(t + 1, t + N + 1); for (int i = 1; i <= N; ++i) a[i] = lower_bound(t + 1, end, s[i]) - t; fill(buc + 1, buc + N + 1, 0); for (int i = 1; i <= N; ++i) ++buc[a[i]]; for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1]; for (int i = 1; i <= N; ++i) rnk[i] = buc[a[i] - 1] + 1; for (int len = 1; len <= N; len <<= 1) { for (int i = 1; i <= N; ++i) { fir[i] = rnk[i]; sec[i] = i + len > N ? 0 : rnk[i + len]; } fill(buc + 1, buc + N + 1, 0); for (int i = 1; i <= N; ++i) ++buc[sec[i]]; for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1]; for (int i = 1; i <= N; ++i) tmp[N - --buc[sec[i]]] = i; fill(buc + 1, buc + N + 1, 0); for (int i = 1; i <= N; ++i) ++buc[fir[i]]; for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1]; for (int i, j = 1; j <= N; ++j) { i = tmp[j]; sa[buc[fir[i]]--] = i; } bool same = false; for (int i, j = 1, last = 0; j <= N; ++j) { i = sa[j]; if (!last) rnk[i] = 1; else if (fir[i] == fir[last] && sec[i] == sec[last]) rnk[i] = rnk[last], same = true; else rnk[i] = rnk[last] + 1; last = i; } if (!same) break; } for (int i = 1, k = 0; i <= N; ++i) { if (rnk[i] == 1) k = 0; else { if (k > 0) --k; int j = sa[rnk[i] - 1]; while (i + k <= N && j + k <= N && a[i + k] == a[j + k]) ++k; } height[rnk[i]] = k; } } bool check(int k) { static int vis[_], tot = 0; int cnt = 0; ++tot; for (int i = 1; i <= N; ++i) { if (height[i] < k) cnt = 0, ++tot; else { if (vis[belong[sa[i]]] != tot) vis[belong[sa[i]]] = tot, ++cnt; if (vis[belong[sa[i - 1]]] != tot) vis[belong[sa[i - 1]]] = tot, ++cnt; if (cnt == n) return true; } } return false; } int main() { #ifndef ONLINE_JUDGE freopen("string.in", "r", stdin); freopen("string.out", "w", stdout); #endif scanf("%d", &n); int now = 0; for (int i = 1; i <= n; ++i) { ++now; scanf("%s", str); int len = strlen(str); for (int j = now; j <= now + len - 1; ++j) s[j] = str[j - now] - 'a' + 1, belong[j] = i; now += len - 1; s[++now] = i + 26; } N = now; SA(); int l = 0, r = N; while (l < r) { int mid = (l + r + 1) >> 1; if (check(mid)) l = mid; else r = mid - 1; } printf("%d\n", l); return 0; }
来源:https://www.cnblogs.com/newbielyx/p/12160645.html