1 条题解
-
0
自动搬运
来自洛谷,原作者为

EuphoricStar
Remember.搬运于
2025-08-24 23:00:34,当前版本为作者最后更新于2024-07-09 20:13:57,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
一个 合法的充要条件为:
- 为 的一个 border;
- 在 中不重叠地出现 次。
建出失配树后,发现合法的 在树上组成一条某个点 到根的链,且 为 的祖先。因此我们若知道 ,答案就是 。
考虑倍增求出 。相当于要 check 这样一个问题:
- 的第 次不重叠出现位置是否 。
考虑预处理出每个前缀 对应的串在整个串中的不重叠出现位置。相当于每次找到一个位置后面第一个后缀,使得它与整个串的 LCP 长度 ,然后跳到它。跳的步数最多是 所以可以暴力跳。
一个后缀与整个串的 LCP 长度可以想到 Z 函数。用并查集维护链表的 trick,从小到大枚举 ,处理完 后把 的所有位置 删了,使得处理到 时,并查集中 的位置为代表元。这样即可 求出一个位置后面第一个 使得 的 。
注意特判 。
总时间复杂度 。
#include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 200100; const int logn = 20; int n, m, fail[maxn], dep[maxn], z[maxn], st[logn][maxn], f[logn][maxn], fa[maxn]; char s[maxn]; vector<int> vc[maxn], cv[maxn]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void solve() { scanf("%d%s%d", &n, s + 1, &m); for (int i = 2, j = 0; i <= n; ++i) { while (j && s[i] != s[j + 1]) { j = fail[j]; } j += (s[i] == s[j + 1]); fail[i] = j; } for (int i = 1; i <= n; ++i) { f[0][i] = fail[i]; dep[i] = dep[fail[i]] + 1; } for (int j = 1; j <= 19; ++j) { for (int i = 1; i <= n; ++i) { f[j][i] = f[j - 1][f[j - 1][i]]; } } z[1] = n; for (int i = 2, l = 0, r = 0; i <= n; ++i) { if (i <= r) { z[i] = min(z[i - l + 1], r - i + 1); } while (i + z[i] <= n && s[z[i] + 1] == s[i + z[i]]) { ++z[i]; } if (i + z[i] - 1 > r) { l = i; r = i + z[i] - 1; } } for (int i = 1; i <= n; ++i) { cv[z[i]].pb(i); fa[i] = (z[i] ? i : i + 1); } fa[n + 1] = n + 1; for (int i = 1; i <= n; ++i) { vc[i].pb(i); int p = i; while (p + i <= n) { int q = find(p + 1); if (q == n + 1) { break; } p = q + i - 1; vc[i].pb(p); } for (int j : cv[i]) { fa[j] = j + 1; } } while (m--) { int x, y; scanf("%d%d", &x, &y); if (y == 1) { puts("1"); continue; } int t = x; for (int i = 19; ~i; --i) { if (f[i][x] && ((int)vc[f[i][x]].size() < y || vc[f[i][x]][y - 1] > t)) { x = f[i][x]; } } x = f[0][x]; printf("%d\n", dep[x]); } } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
- 1
信息
- ID
- 10272
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者