P9873 [EC Final 2021] Beautiful String

· · 题解

题目要求形如 AABCAB 的子串的个数。观察到其中有两个 AB,考虑去枚举第一个 AB,那么满足要求的子串就是 AB 前面紧跟着一个它的前缀,在它后面还有一个 AB 不与它相邻。

设第一个 AB 的第一个字符在位置 i,第二个 AB 的第一个字符在位置 jl_1 = |A|, l_2 = |AB|,为了保证 A 非空,l_1 < l_2

那么前后能匹配的最大长度就是 ma = \min \{j - i - 1, lcp_{i, j}\},其中 lcp_{i, j} 表示以 i 开头的后缀和以 j 开头的后缀的最长公共前缀,可以 O(n ^ 2) 预处理,j - i - 1 是因为要保证它们不相邻,所以长度最大为这么多。

答案即为:

\sum _i \sum _j \sum _{l_2 = 1} ^{ma} \sum _{l_1 = 1} ^{l_2 - 1} [lcp_{i - l_1, i} \ge l_1] 将内层循环展开: $$ \begin{aligned} \sum _{l_1 = 1} ^{ma - 1} (ma - l_1)\times [lcp_{i - l_1, i} \ge l_1] \end{aligned} $$ 继续展开并整理可得原式是以下项的和: $$ \begin{aligned} &l_1 = 1: [lcp_{i - 1, i} \ge 1] \\ &l_1 = 2: [lcp_{i - 1, i} \ge 1], [lcp_{i - 2, i} \ge 2] \\ &l_1 = 3: [lcp_{i - 1, i} \ge 1], [lcp_{i - 2, i} \ge 2], [lcp_{i - 3, i} \ge 3] \\ \vdots \\ &l_1 = ma - 1: [lcp_{i - 1, i} \ge 1], [lcp_{i - 2, i} \ge 2], [lcp_{i - 3, i} \ge 3] , \dots, [lcp_{i - ma + 1, i} \ge ma - 1] \end{aligned} $$ 应该很好想了,发现每一行行内可以前缀和优化,之后再将每一行做前缀和。 具体地,设 $$ \begin{aligned} &f_{i, j} = \sum \limits _{k = 1} ^j [lcp_{i - k, i} \ge j] \\ &g_{i, j} = \sum _{k = 1} ^ j (j - k + 1) \times [lcp_{i - k, i} \ge k] = \sum \limits _{k = 1} ^j f_{i, k} \end{aligned} $$ 最后答案为 $\sum \limits _i \sum \limits _j g_{i, ma - 1}$,注意越界处理。 时间复杂度 $O(n ^ 2)$。 ## 代码 ```cpp CI N = 5e3 + 5; int n, ans, lcp[N][N], f[N][N], g[N][N]; std::string s; signed main() { int T = read(); while(T --) { std::cin >> s, n = s.size(), s = " " + s, ans = 0; dep(i, n, 1) dep(j, n, i) if(s[i] == s[j]) lcp[i][j] = lcp[i + 1][j + 1] + 1; rep(i, 1, n) rep(j, 1, n) f[i][j] = i - j >= 0 ? f[i][j - 1] + (lcp[i - j][i] >= j) : f[i][i]; rep(i, 1, n) rep(j, 1, n) g[i][j] = g[i][j - 1] + f[i][j]; rep(i, 2, n) rep(j, i + 3, n - 1) ans += g[i][std::max(1ll, std::min(j - i - 1, lcp[i][j])) - 1]; printl(ans); rep(i, 1, n) rep(j, 1, n) lcp[i][j] = f[i][j] = g[i][j] = 0; } return 0; } ```