[bzoj 3172][tjoi 2013] 单词

题目大意

给定词典 (D),词典中的单词连起来(单词间分割开来)为文章。求每个单词在文章中的出现次数。

(1 leqslant |D| leqslant 200)

(1 leqslant |T| leqslant 1,000,000)

题目链接

BZOJ 3172

CodeVS 2542

题解

AC 自动机模版题。

单词间用字符集外的字符连接。

代码

为了让儿子数少点,<code> 是ASCII中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
73
74
75
76
77
78
79
80

#include <cstring>
#include <queue>
const int MAXN = 205;
const int MAXLEN = 1000005;
const int CHARSET_SIZE = 'z' - ''</span> + <span class="number">1</span>;</span><br/><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> BASE_CHAR = <span class="string">'';
struct {
struct Node {
Node *c[CHARSET_SIZE], *fail, *next;
bool isWord;
int ans;
Node(bool isWord = false) : isWord(isWord), fail(NULL), next(NULL), ans(0) {
for (int i = 0; i < CHARSET_SIZE; i++) c[i] = NULL;
}
void apply() {
ans++;
if (next) next->apply();
}
} *root;
Trie() : root(NULL) {}
Node *insert(char *begin, char *end) {
Node **u = &root;
for (char *p = begin; p != end; p++) {
if (!(*u)) *u = new Node();
u = &(*u)->c[*p];
}
if (!(*u)) *u = new Node(true);
else (*u)->isWord = true;
return *u;
}
void build() {
std::queue<Node *> q;
q.push(root);
root->fail = root;
root->next = NULL;
while (!q.empty()) {
Node *u = q.front();
q.pop();
for (int i = 0; i < CHARSET_SIZE; i++) {
Node *c = u->c[i];
if (!c) continue;
Node *v = u->fail;
while (v != root && !v->c[i]) v = v->fail;
c->fail = u != root && v->c[i] ? v->c[i] : root;
c->next = c->fail->isWord ? c->fail : c->fail->next;
q.push(c);
}
}
}
void exec(char *begin, char *end) {
Node *u = root;
for (char *p = begin; p != end; p++) {
while (u != root && !u->c[*p]) u = u->fail;
u = u->c[*p] ? u->c[*p] : root;
if (u->isWord) u->apply();
else if (u->next) u->next->apply();
}
}
} t;
int main() {
int n;
scanf("%d", &n);
static Trie::Node *words[MAXN];
static char str[MAXLEN + MAXN];
char *p = str;
for (int i = 0; i < n; i++) {
static char s[MAXLEN];
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len; i++) s[i] -= BASE_CHAR, *p++ = s[i];
words[i] = t.insert(s, s + len);
*p++ = 0;
}
*--p = 0;
t.build();
t.exec(str, p);
for (int i = 0; i < n; i++) printf("%dn", words[i]->ans);
return 0;
}