「TJOI2019」甲苯先生和大中锋的字符串

#3108. 「TJOI2019」甲苯先生和大中锋的字符串

Summarize

给定字符串 $s$,求出 $s$ 恰好出现 $k$ 次的子串中长度中出现次数最多的长度数。

$|s|\le 100000$

Solution

对原串建立后缀自动机。

可以通过一遍 dfs 求出 $\text{parent}$ 树上每个节点的出现次数。对于出现次数恰好为 $k$ 的节点,则将该节点覆盖的长度区间加一,可以用差分数组处理。

在差分数组中找出答案即可。

Note

后缀自动机多测清空时注意将 $\text{trans}$ 数组清空,尤其是 $0$ 号节点。

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <bits/stdc++.h>
using namespace std;

const int SIGMA = 27;
const int MAXN = 2e5 + 5;

int n, k;
int f[MAXN << 1], s[MAXN << 1];

struct SAM {
struct Node {
int len, link;
int trans[SIGMA];
} node[MAXN << 1];
#define len(u) node[u].len
#define link(u) node[u].link
#define trans(u, c) node[u].trans[c]
int cnt, last;
void init() {
len(0) = 0;
link(0) = -1;
cnt = 0;
last = 0;
for (int i = 0; i < SIGMA; ++i)
trans(0, i) = 0;
}
void insert(int c) {
int cur = ++cnt;
for (int i = 0; i < SIGMA; ++i)
trans(cur, i) = 0;
len(cur) = len(last) + 1;
int p = last;
while (p != -1 && trans(p, c) == 0) {
trans(p, c) = cur;
p = link(p);
}
if (p == -1) {
link(cur) = 0;
} else {
int q = trans(p, c);
if (len(p) + 1 == len(q)) {
link(cur) = q;
} else {
int clone = ++cnt;
for (int i = 0; i < SIGMA; ++i)
trans(clone, i) = 0;
len(clone) = len(p) + 1;
for (int i = 0; i < SIGMA; ++i)
trans(clone, i) = trans(q, i);
link(clone) = link(q);
while (p != -1 && trans(p, c) == q) {
trans(p, c) = clone;
p = link(p);
}
link(q) = link(cur) = clone;
}
}
f[cur] = 1;
last = cur;
}
} T;

struct Edge {
int v, nxt;
} edge[MAXN << 1];
int head[MAXN << 1], cnt;
void AddEdge(int u, int v) {
edge[++cnt].v = v;
edge[cnt].nxt = head[u];
head[u] = cnt;
}

void dfs(int u) {
for (int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].v;
dfs(v);
f[u] += f[v];
}
if (u == 0) return;
if (f[u] == k) {
int l = T.node[T.node[u].link].len + 1;
int r = T.node[u].len;
s[l] += 1;
s[r + 1] -= 1;
}
}


int t;
char str[MAXN];

int main() {
scanf("%d", &t);
while (t--) {
T.init();
scanf("%s", str + 1);
n = strlen(str + 1);
scanf("%d", &k);
for (int i = 1; i <= n; ++i)
T.insert(str[i] - 'a');
for (int i = 1; i <= T.cnt; ++i) {
AddEdge(T.node[i].link, i);
}
dfs(0);
int ans = -1, ans_val = 0;
for (int i = 1; i <= n; ++i) {
s[i] += s[i - 1];
if (s[i] && s[i] >= ans_val)
ans = i, ans_val = s[i];
}
printf("%d\n", ans);
for (int i = 0; i <= T.cnt; ++i) {
f[i] = 0;
head[i] = 0;
s[i] = 0;
}
cnt = 0;
}
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×