parent 树上启发式合并
parent 树上启发式合并
题目描述
$LH$ 拿到了一个字符串 $S$,他想要和你玩个游戏,每次 $LH$ 询问你一个字符串 $T$,和一个整数 $k$,你需要回答,字符串 $T$ 在 $S$ 中从左到右出现第 $k$ 次的位置在哪。
假如 $S[l \sim r]=T$,那么字符串 $T$ 在位置 $r$ 出现。
字符串中只可能出现小写英文字母,大写英文字母和阿拉伯数字。
输入描述:
第一行输入两个整数 $n(1 \leq n \leq 10^5 ),q(1 \leq q \leq 10^5)$,分别表示 $S$ 的长度和询问次数。
第二行包含一个字符串 $S$。
随后 $q$ 行,每行包含一个字符串 $T$ 和一个正整数 $k(1 \leq k \leq 10^5)$。
保证所有询问的不同的字符串 $T$ 的长度和不超过 $10^4$ 。
保证所有询问的字符串 $T$ 的长度和不超过 $10^5$ 。
字符串可能包含英文小写字母,英文大写字母,数字。
提示:请注意不寻常的内存限制。
输出描述:
对于每个询问,输出 $T$ 在 $S$ 中出现第 $k$ 次的下标,假如 $T$ 在 $S$ 中的出现次数少于 $k$ 次,请输出 $−1$。
示例1
输入
10 5
abcabC8dab
ab 3
abc 1
e 1
b 2
abced 2
输出
10
3
-1
5
-1
解题思路
显然我们不可能单独处理每个询问。本题关键的地方在于,要对询问的字符串长度分类处理。
假设询问的字符串总长度为 $m$,那么字符串长度的种类最多有 $O(\sqrt{m})$ 种。此时我们就可以反过来考虑,进行离线处理。枚举这 $O(\sqrt{m})$ 种长度,对于长度 $\text{len}$,将字符串 $s$ 中所有长度为 $\text{len}$ 的子串的出现位置存储下来。然后枚举所有的询问,如果字符串 $t$ 的出现位置至少记录了 $k$ 次,则找到了该询问的答案。
另外为了方便映射子串对应的出现位置,以及进行字符串比较,需要对 $s$ 和每个 $t$ 进行字符串哈希。
AC 代码如下,时间复杂度为 $O((n+q)\sqrt{m}\log{n})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5 + 5, P = 13331;
char s[N];
ULL h[N], p[N];
array<ULL, 2> q[N];
set<int> st[N];
int ans[N];
ULL query(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
int n, m;
scanf("%d %d %s", &n, &m, s + 1);
p[0] = 1;
for (int i = 1; i <= n; i++) {
h[i] = h[i - 1] * P + s[i];
p[i] = p[i - 1] * P;
}
for (int i = 0; i < m; i++) {
int x;
scanf("%s %d", s, &x);
int len = strlen(s);
ULL t = 0;
for (int i = 0; i < len; i++) {
t = t * P + s[i];
}
q[i] = {t, ULL(x)};
st[len].insert(t);
}
for (int i = 1; i < N; i++) {
if (st[i].empty()) continue;
map<ULL, vector<int>> mp;
for (int j = i; j <= n; j++) {
ULL t = query(j - i + 1, j);
if (st[i].count(t)) mp[t].push_back(j); // 需要加上该的判断剪枝,否则会超时
}
for (int i = 0; i < m; i++) {
if (q[i][1] <= mp[q[i][0]].size()) ans[i] = mp[q[i][0]][q[i][1] - 1];
}
}
for (int i = 0; i < m; i++) {
printf("%d\n", ans[i] ? ans[i] : -1);
}
return 0;
}
最小代价构造字符串,图上计数(Hard) 都用到了类似思想。
参考资料
牛客小白月赛97题解:https://www.nowcoder.com/discuss/636309017548120064
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18309785

浙公网安备 33010602011771号