思路
这道题就是一道 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;
}
// 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;
}
// 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; }