1. 程式人生 > 其它 >【luogu P5546】公共串

【luogu P5546】公共串

技術標籤:# 二分# 字串二分SA字尾陣列字串基數排序

公共串

題目連結:luogu P5546

題目大意

給出幾個字串,求它們的最長公共子串。

思路

這題其實跟最長公共子串屎很像的,你只要不用把字串翻轉得到的字串也弄進去,以及改一下陣列和一些變數的範圍大小。

因為思路是一樣的,就不做註釋,去那一篇看吧。

程式碼

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int n, m, T, t;
int p,
tmp, sn, c[200001], height[200001], str[200001]; int sa[200001], rak[200001], tp[200001], tax[200001]; char s[200001]; queue <int> q; bool in[200001]; void csh() { n = 0; tmp = 0; memset(sa, 0, sizeof(sa)); memset(rak, 0, sizeof(rak)); memset(tp, 0, sizeof(tp)); memset(tax, 0, sizeof(tax)); memset(c, 0, sizeof(c)); memset(s, 0
, sizeof(s)); memset(height, 0, sizeof(height)); memset(str, 0, sizeof(str)); memset(in, 0, sizeof(in)); } void paixu() { for (int i = 1; i <= m; i++) tax[i] = 0; for (int i = 1; i <= n; i++) tax[rak[i]]++; for (int i = 2; i <= m; i++) tax[i] += tax[i - 1]; for (int i = n; i >=
1; i--) sa[tax[rak[tp[i]]]--] = tp[i]; } void SA() { for (int i = 1; i <= n; i++) { rak[i] = c[i]; tp[i] = i; } m = 1000; paixu(); for (int w = 1; w < n; w <<= 1) { m = p; p = 0; for (int i = n - w + 1; i <= n; i++) tp[++p] = i; for (int i = 1; i <= n; i++) if (sa[i] > w) tp[++p] = sa[i] - w; paixu(); swap(tp, rak); p = 1; rak[sa[1]] = 1; for (int i = 2; i <= n; i++) if (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w]) rak[sa[i]] = p; else rak[sa[i]] = ++p; if (p == n) break; } } void get_height() { int now = 0; for (int i = 1; i <= n; i++) rak[sa[i]] = i; for (int i = 1; i <= n; i++) { if (now) now--; for (int j = sa[rak[i] - 1]; c[i + now] == c[j + now]; now++); height[rak[i]] = now; } } bool check(int mid) { while (!q.empty()) q.pop(); memset(in, 0, sizeof(in)); for (int i = 2; i <= n; i++) if (height[i] >= mid) { if (!in[str[sa[i]]]) { q.push(str[sa[i]]); in[str[sa[i]]] = 1; } if (!in[str[sa[i - 1]]]) { q.push(str[sa[i - 1]]); in[str[sa[i - 1]]] = 1; } } else { if (q.size() == t) return 1; while (!q.empty()) q.pop(); memset(in, 0, sizeof(in)); } if (q.size() == t) return 1; return 0; } void work() { if (t == 1) { printf("%d\n", sn); return ; } int lef = 0, rig = 2000, re = 0; while (lef <= rig) { int mid = (lef + rig) >> 1; if (check(mid)) { re = mid; lef = mid + 1; } else rig = mid - 1; } printf("%d\n", re); } int main() { // scanf("%d", &T); // for (int times = 1; times <= T; times++) { // csh(); // scanf("%d", &t); for (int ii = 1; ii <= t; ii++) { scanf("%s", s + 1); sn = strlen(s + 1); for (int i = 1; i <= sn; i++) { c[++n] = s[i] - 'a' + 2 * t + 1; str[n] = ii; } c[++n] = ++tmp; str[n] = ii; } SA(); get_height(); work(); // } return 0; }