题目描述
对于一对字符串 \((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; }
|