P6216 回文匹配

P6216 回文匹配

题目描述

对于一对字符串 \((s_1,s_2)\),若 \(s_1\) 的长度为奇数的子串 \((l,r)\) 满足 \((l,r)\) 是回文的,那么 \(s_1\) 的“分数”会增加 \(s_2\)\((l,r)\) 中出现的次数。

现在给出一对 \((s_1,s_2)\),请计算出 \(s_1\) 的“分数”。

答案对 \(2 ^ {32}\) 取模。

输入格式

第一行两个整数,\(n,m\),表示 \(s_1\) 的长度和 \(s_2\) 的长度。

第二行两个字符串,\(s_1,s_2\)

输出格式

一行一个整数,表示 \(s_1\) 的分数。

分析

所以对于一个回文中心为 \(i\) 的答案:

\[ ans_i=\sum_{p=0}^{p_i}sum^\prime_{i+p-len_b}-sum^\prime_{i-p}[p\times 2-1\ge len_b] \] 然后可以把这个布尔表达式拉出来康康: \[ p\times 2-1\ge len_b\\ p\times 2\ge len_b+1\\ p\ge\left\lceil\frac{len_b+1}{2}\right\rceil \] 所以还可以这样表达: \[ mid=\left\lceil\frac{len_b+1}2\right\rceil\\ ans_i=\sum_{p=mid}^{p_i}sum^\prime_{i+p-len_b}-sum^\prime_{i-p} \] 所以答案就可以写成: \[ \begin{aligned} ans &= \sum_{i=mid}^{len_a}\sum_{p=mid}^{p_i}sum^\prime_{i+p-len_b}-sum^\prime_{i-p}\\ ans &= \sum_{i=mid}^{len_a}(\sum_{p=mid}^{p_i}sum^\prime_{i+p-len_b})-(\sum_{p=mid}^{p_i}sum^\prime_{i-p})\\ ans &= \sum_{i=mid}^{len_a}(sum^{\prime\prime}_{i+p_i-len_b}-sum^{\prime\prime}_{i+mid-len_b})-(sum^{\prime\prime}_{i-mid}-sum^{\prime\prime}_{i-len_b})\\ \end{aligned} \] 所以就可以 \(KMP\) 玩了以后做一个二阶的前缀和,然后就这样就可以了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <bits/stdc++.h>

using namespace std;

const int maxn = 3e6 + 10;
char a[maxn], b[maxn];
int lena, lenb, sum[maxn];
int pre[maxn], p[maxn];
unsigned int ans;

inline void kmp()
{
for (int i = 2, nxt = 0; i <= lenb; ++i) {
while (nxt && b[nxt + 1] != b[i]) nxt = pre[nxt];
if (b[nxt + 1] == b[i]) ++nxt;
pre[i] = nxt;
}

for (int i = 1, nxt = 0; i <= lena; ++i) {
while (nxt && b[nxt + 1] != a[i]) nxt = pre[nxt];
if (b[nxt + 1] == a[i]) ++nxt;
if (nxt == lenb) {
nxt = pre[nxt];
sum[i - lenb + 1] = 1;
}
}

for (int i = 1; i <= lena; ++i) sum[i] += sum[i - 1];
for (int i = 1; i <= lena; ++i) sum[i] += sum[i - 1];
}

inline void manacher()
{
int mx(0), id(0);
p[0] = '#', p[lena + 1] = '&';
for (int i = 1; i <= lena; ++i) {
if (mx > i) p[i] = min(p[id * 2 - i], mx - i);
else p[i] = 1;

while (a[i - p[i]] == a[i + p[i]] && i - p[i] >= 1 && i + p[i] <= lena) ++p[i];
if (i + p[i] > mx) mx = p[i] + i, id = i;
}
}

inline int Sum(int l, int r)
{
return sum[r] - sum[l - 1];
}

int main()
{
scanf ("%d %d", &lena, &lenb);
scanf ("%s %s", a + 1, b + 1);

kmp();
manacher();

int mid = ceil((lenb + 1)/2.0);
for (int i = mid; i <= lena; ++i) {
if (2 * p[i] - 1 < lenb) continue;
ans += Sum(i - lenb + mid, i - lenb + p[i]);
ans -= Sum(i - p[i], i - mid);
}
cout << ans << endl;
}