0%

CF432D Prefixes and Suffixes

传送门

Solution

使用扩展 KMP 求出 ziz_i。设字符串 SS 长度为 nn,下标从 00 开始。某前缀同时也是后缀,当且仅当 i+zi=ni+z_i=n 符合要求的 ziz_i 数量即为完美子串数量。ziz_i 对应的完美字串在 SS 中的出现次数,等于满足 jij\neq izjziz_j\ge z_ijj 数量。可用权值树状数组计算 jj 的数量。

时间复杂度 O(nlogn)O(n\log n)

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
#include <bits/stdc++.h>
using namespace std;

const int N = 100010;

int z[N], l, r, ans[N], ans_cnt, tr[N], n, cntn;
string s;

int lowbit(int x) {return x & -x;}

void add(int x, int c)
{
for (; x <= n; x += lowbit(x))
tr[x] += c;
}

int query(int x)
{
int res = 0;
for (; x > 0; x -= lowbit(x))
res += tr[x];
return res;
}

int main()
{
cin >> s; n = s.size();
cntn = n - 1;
for (int i = 1; i < n; i++) {
if (i <= r && z[i - l] < r - i + 1)
z[i] = z[i - l];
else {
z[i] = max(r - i + 1, 0);
while (i + z[i] < n && s[i + z[i]] == s[z[i]])
++z[i];
}
if (i + z[i] - 1 > r) {
l = i;
r = i + z[i] - 1;
}
if (i + z[i] == n)
ans[++ans_cnt] = z[i];
if (z[i] > 0)
add(z[i], 1);
else
--cntn;
}
sort(ans + 1, ans + ans_cnt + 1);
printf("%d\n", ans_cnt + 1);
for (int i = 1; i <= ans_cnt; i++) {
add(ans[i], -1);
int cnt = cntn - 1 - query(ans[i] - 1);
add(ans[i], 1);
printf("%d %d\n", ans[i], cnt + 2);
}
printf("%d 1\n", n);
return 0;
}