「BZOJ-3940&3942」Censoring (字符串)

给定一个字符串S,给定一个模式串/n个模式串,从前往后寻找,一旦找到模式串,删除该模式串并继续从头寻找。重复这一过程,直到S中不存在模式串,输出最后的S。

好了这是Usaco月赛里面题意和做法都非常相似的两个题,分别是KMP和AC自动机的应用。

Sliver

BZOJ3942 - [Usaco2015 Feb]Censoring

题意

给出两个字符串 $S$ 和 $T$,每次从前往后找到$S$ 的一个子串 $A=T$并将其删除,空缺位依次向前补齐,重复上述操作多次,直到串$S$中不含 $T$串。输出最终的$S$串。

思路

用栈维护给定的$S$串,对$s$依次入栈并求当前位的$next$数组,如果匹配到$T$,将长度为$len(T)$的字符出栈。对于每个入栈元素,取当前栈顶元素即可求出当前元素的$next$数组指向位置,直到$S$全部入栈。输出栈内元素即为答案。

代码

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

using namespace std;

const int maxn = 1e6 + 10;

char a[maxn], b[maxn], st[maxn];
int nex[maxn], p[maxn];

void getNext() {
int len = strlen(b), i = 0, j = -1;
nex[0] = -1;
for (int i = 1; i < len; i++) {
while (j != -1 && b[i] != b[j + 1]) j = nex[j];
if (b[i] == b[j + 1])
j++;
nex[i] = j;
}
}

void KMP() {
int n = strlen(a), m = strlen(b);
getNext();
int top = 0;
for (int i = 0; i < n; i++) {
int j = p[top];
st[++top] = a[i];
while (j != -1 && b[j + 1] != st[top]) j = nex[j];
if (b[j + 1] == st[top])
j++;
p[top] = j;
if (p[top] + 1 == m)
top -= m;
}
st[top + 1] = 0;
puts(st + 1);
}

int main() {
scanf("%s%s", a, b);
KMP();
return 0;
}

Gold

BZOJ3940 - [Usaco2015 Feb]Censoring

题意

给定一个串$S$和$n$个屏蔽词$T_n$,对于串$S$,每次从前往后检查并删除最先出现的屏蔽词,重复该操作直到$S$中没有列表内的单词为止。完成这些操作并输出最后的$S$。

思路

同样由栈维护母串$S$,并记录栈中每个字符在Trie树上的位置,如果遇到关键串,将该串推出栈中,每次入栈前取当前栈顶字符在Trie树上的位置即可求出当前串的位置。

代码

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

using namespace std;

const int maxn = 1e5 + 10;

char s[maxn], t[maxn];

class ACAutomation {
public:
int trie[maxn][26], cnt;
int tag[maxn];
int fail[maxn];
int st[maxn], pos[maxn], cur;

void insert(char *s) {
int root = 0;
for (int i = 0; s[i]; i++) {
int id = s[i] - 'a';
if (!trie[root][id])
trie[root][id] = ++cnt;
root = trie[root][id];
}
tag[root] = strlen(s);
}

void build() {
queue<int> que;
for (int i = 0; i < 26; i++)
if (trie[0][i])
que.push(trie[0][i]);
while (!que.empty()) {
int k = que.front();
que.pop();
for (int i = 0; i < 26; i++) {
if (trie[k][i]) {
fail[trie[k][i]] = trie[fail[k]][i];
que.push(trie[k][i]);
} else
trie[k][i] = trie[fail[k]][i];
}
}
}

void query() {
int root = 0;
pos[0] = 0;
for (int i = 0; t[i]; i++) {
root = trie[pos[cur]][t[i] - 'a'];
st[++cur] = t[i] - 'a';
pos[cur] = root;
if (tag[root]) {
cur -= tag[root];
root = pos[cur];
}
}
for (int i = 1; i <= cur; i++) printf("%c", st[i] + 'a');
printf("\n");
}
} AC;

int main() {
int n;
scanf("%s", t);
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%s", s);
AC.insert(s);
}
AC.build();
AC.query();
return 0;
}