Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P7114 [NOIP2020] 字符串匹配

P7114 [NOIP2020] 字符串匹配

考虑对于每个前缀求出循环多少次,求出 Z 函数,那么 $\frac { z _ i } i$ 即为循环次数。考虑不同的循环次数,奇偶分开讨论,对于奇数次,每增加两次循环对 C 前后出现奇数次字符的个数没有影响,只需考察这个前缀中 A 的划分即可,满足 $F(A) \le F(C)$ 即可。对于偶数次,$F(C) = F(S)$ ,不用再单独计算,每个 $A$ 的划分都可以作为答案。枚举前缀的同时维护 $A$ 。

查看代码
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
66
67
68
69
70
71
72
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
template <class Type>
void read (Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
if (c == '-') flag = true;
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0';
if (flag) x = ~x + 1;
}
template <class Type, class ...Rest>
void read (Type &x, Rest &...y) { read(x), read(y...); }
template <class Type>
void write (Type x)
{
if (x < 0) putchar('-'), x = ~x + 1;
if (x > 9) write(x / 10);
putchar('0' + x % 10);
}
typedef long long L;
const int N = (1 << 20) + 10, M = 27;
char str[N];
bool g[2][M];
int n, z[N], f[2], h[M];
void init ()
{
z[0] = 0;
for (int i = 1, t = 0; i < n; ++i)
{
z[i] = 0;
if (t + z[t] > i) z[i] = min(z[i - t], t + z[t] - i);
while (i + z[i] < n && str[z[i]] == str[i + z[i]]) ++z[i];
if (i + z[i] > t + z[t]) t = i;
}
}
void add (bool op, int c) { f[op] += (g[op][c] ^= 1) & 1 ? 1 : -1; }
int main ()
{
int T; read(T);
while (T--)
{
scanf("%s", str);
n = strlen(str);
init();
for (int i = 0; i < n; ++i) add(1, str[i] - 'a');
int x = f[1];
L res = 0;
for (int i = 0; i < n; ++i)
{
add(0, str[i] - 'a'), add(1, str[i] - 'a');
if (i > 0 && i < n - 1)
{
int t = z[i + 1] / (i + 1) + 1;
if (t * (i + 1) == n) --t;
int a = t >> 1, b = t - a;
for (int j = 0; j <= x; ++j) res += (L)a * h[j];
for (int j = 0; j <= f[1]; ++j) res += (L)b * h[j];
}
++h[f[0]];
}
write(res), puts("");
for (int i = n - 1; ~i; --i)
--h[f[0]], add(0, str[i] - 'a');
}
return 0;
}