思路
这道题就是一道 AC 自动机的模板题。AC 自动机适用于多个模式串匹配的情景,实际上,它就是在 Trie 树上进行的一个匹配算法。这里有一篇很优秀的讲稿,不了解 AC 自动机的读者可以自行阅读:https://blog.csdn.net/creatorx/article/details/71100840
这道题我们只需要在 Trie 树上增加一个关键字 \(sum\) 即可。
代码
// HDU-2222.cpp #include <iostream> #include <queue> #include <cstdio> #include <cstring> using namespace std; struct node { node *nxt[26], *fail; int sum; ~node() { for (int i = 0; i < 26; i++) if (nxt[i] != NULL) delete nxt[i]; } }; node *root; int cnt; char str[1000020]; void insert(string str) { int siz = str.length(); node *p = root; for (int i = 0; i < siz; i++) { int curt = str[i] - 'a'; if (p->nxt[curt] == NULL) { p->nxt[curt] = new node(); p->nxt[curt]->fail = NULL; for (int i = 0; i < 26; i++) p->nxt[curt]->nxt[i] = NULL; p->nxt[curt]->sum = 0; } p = p->nxt[curt]; } p->sum++; } void build_AC_automation() { queue<node *> q; q.push(root); node *p, *tmp; while (!q.empty()) { tmp = q.front(); q.pop(); for (int i = 0; i < 26; i++) if (tmp->nxt[i]) { if (tmp == root) tmp->nxt[i]->fail = root; else { p = tmp->fail; while (p) if (p->nxt[i]) { tmp->nxt[i]->fail = p->nxt[i]; break; } else p = p->fail; if (p == NULL) tmp->nxt[i]->fail = root; } q.push(tmp->nxt[i]); } } } void ac_automation(string passage) { int siz = passage.length(); node *p = root; for (int i = 0; i < siz; i++) { int curt = passage[i] - 'a'; while (!p->nxt[curt] && p != root) p = p->fail; p = p->nxt[curt]; if (p == NULL) p = root; node *tmp = p; while (tmp != root) { if (tmp->sum >= 0) { cnt += tmp->sum; tmp->sum = -1; } else break; tmp = tmp->fail; } } } int main() { int T; scanf("%d", &T); while (T--) { int n; scanf("%d", &n); root = new node(); for (int i = 1; i <= n; i++) scanf("%s", str), insert(str); build_AC_automation(); scanf("%s", str); ac_automation(str); printf("%d\n", cnt); cnt = 0; } return 0; }