洛谷 P10716 【MX-X1-T4】「KDOI-05」简单的字符串问题
一个 合法的充要条件为:
- 为 的一个 border;
- 在 中不重叠地出现 次。
建出失配树后,发现合法的 在树上组成一条某个点 到根的链,且 为 的祖先。因此我们若知道 ,答案就是 。
考虑倍增求出 。相当于要 check 这样一个问题:
- 的第 次不重叠出现位置是否 。
考虑预处理出每个前缀 对应的串在整个串中的不重叠出现位置。相当于每次找到一个位置后面第一个后缀,使得它与整个串的 LCP 长度 ,然后跳到它。跳的步数最多是 所以可以暴力跳。
一个后缀与整个串的 LCP 长度可以想到 Z 函数。用并查集维护链表的 trick,从小到大枚举 ,处理完 后把 的所有位置 删了,使得处理到 时,并查集中 的位置为代表元。这样即可 求出一个位置后面第一个 使得 的 。
注意特判 。
总时间复杂度 。
code
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
2023-07-17 20230717 讲题
2023-07-17 CodeForces 1848E Vika and Stone Skipping