題目鏈接
https://www.luogu.org/problem/P5410
分析
國外一般稱此算法爲Z Algorithm,個人感覺算法思想上和Manacher算法更爲接近;
設 表示模式串 後綴 與 的最大公共前綴長度;
若已求 ,接下來要求 ,
記錄當前擴展最遠的點,即 ,
由 數組定義可知,,
而 ,
且 ,
故有 ,
若 未到達擴展到的最遠位置,則 便可確定;
否則,暴力先後擴展,並更新擴展到的最遠位置,
仿照KMP算法,利用 數組求出原問題答案;
擴展到的最遠位置要麼增加,要麼不變,複雜度爲 。
AC代碼
#include <cstdio>
#include <cstring>
const int maxn = 1e5 + 5;
int nxt[maxn], ex[maxn], l1, l2;
char a[maxn], b[maxn];
inline void get_nxt() {
nxt[1] = l2;
for (int i = 1; i < l2 && b[i] == b[i + 1]; ++i) ++nxt[2];
int k = 2;
for (int i = 3; i <= l2; ++i) {
int p = k + nxt[k] - 1;
if (i + nxt[i - k + 1] - 1 < p) nxt[i] = nxt[i - k + 1];
else {
int j = p - i + 1;
if (j < 1) j = 1;
while (i + j - 1 <= l2 && b[i + j - 1] == b[j]) ++j;
nxt[i] = j - 1, k = i;
}
}
}
inline void exkmp() {
get_nxt();
for (int i = 1; i <= l1 && i <= l2; ++i) {
if (a[i] != b[i]) break;
++ex[1];
}
int k = 1;
for (int i = 2; i <= l1; ++i) {
int p = k + ex[k] - 1;
if (i + nxt[i - k + 1] - 1 < p) ex[i] = nxt[i - k + 1];
else {
int j = p - i + 1;
if (j < 1) j = 1;
while (i + j - 1 <= l1 && j <= l2 && a[i + j - 1] == b[j]) ++j;
ex[i] = j - 1, k = i;
}
}
}
int main() {
scanf("%s%s", a + 1, b + 1);
l1 = strlen(a + 1), l2 = strlen(b + 1);
exkmp();
for (int i = 1; i <= l2; ++i) printf("%d ", nxt[i]);
puts("");
for (int i = 1; i <= l1; ++i) printf("%d ", ex[i]);
return 0;
}