![在这里插入图片描述](https://img-blog.csdnimg.cn/20210302162959981.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzkxNDg0,size_16,color_FFFFFF,t_70)
题解
- hash前面已经讲过了,我们再用KMP做一下,对于KMP我们先要了解ne数组:next[i]=j 以i为终点的后缀和从1开始的非平凡前缀最大重合是j
- 我们先对B预处理出ne,然后对A进行匹配
for (int i = 1, j = 0; i <= n; i++) {
while (j && a[i] != b[j + 1]) j = ne[j];
if (a[i] == b[j + 1]) j++;
cnt[j]++;
}
- 我们知道,对于 j 表示的是B能匹配A以i结尾的最长长度是j ,也就是说,在A中子串A[i-j+1,i] 与 B[1,j] 相同(字符串 A 中,以 i−j+1 为起点的与 B 匹配的长度最小为 j),那么我们就用一个数组cnt[x]来记录满足匹配前缀至少为x的后缀的数量
- 我们继续看,对于cnt[j],能匹配,那么cnt[cnt[j]]也一定能和言字符串匹配,那么我们就可以拓扑序累加,计算出所有的cnt数组
- 最后 cnt[i] 存的是满足匹配的前缀至少为 x 的后缀数量,而题目中所要求的满足匹配的前缀恰好为 x 的答案的应为匹配的前缀至少为 x 的后缀数量 减去 匹配的前缀至少为 x + 1 的后缀数量,即 cnt[x] - cnt[x + 1](后缀和思想)
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N = 2e5 + 10;
int n, m, q, x;
char a[N], b[N];
int ne[N], cnt[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
cin >> n >> m >> q;
cin >> a + 1 >> b + 1;
for (int i = 2, j = 0; i <= m; i++) {
while (j && b[i] != b[j + 1]) j = ne[j];
if (b[i] == b[j + 1]) j++;
ne[i] = j;
}
for (int i = 1, j = 0; i <= n; i++) {
while (j && a[i] != b[j + 1]) j = ne[j];
if (a[i] == b[j + 1]) j++;
cnt[j]++;
}
for (int i = m; i > 0; i--) cnt[ne[i]] += cnt[i];
while (q--) {
cin >> x;
cout << cnt[x] - cnt[x + 1] << endl;
}
return 0;
}