感谢 小白菜菜菜 的更正,让我可以拥有更简洁的模板!
参考:AC自动机总结
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
const int N = 5e5+5, M = 1e6+5;
struct Trie {
Trie *next[26];
Trie *fail;
int val;
}tree[N];
queue <Trie *> q;
int idx[128];
class ac_auto {
private:
int nxt;
Trie *root;
public:
ac_auto() {
nxt = 0;
root = add();
}
Trie *add() {
memset(&tree[nxt], 0, sizeof(Trie));
return &tree[nxt++];
}
void insert(char *s) {
Trie *rt = root;
int len = strlen(s);
for(int i = 0; i < len; i++) {
int c = idx[s[i]+0];
if(!rt->next[c])
rt->next[c] = add();
rt = rt->next[c];
}
rt->val = 1;//rt->val++;用于统计
}
void get_f() {
queue <Trie *> q;
q.push(root);
root->fail = NULL;
while(!q.empty()) {
Trie *u = q.front(); q.pop();
for(int c = 0; c < 26; c++) {
if(u->next[c]) {
Trie *f = u->fail;
while(f && !f->next[c]) f = f->fail;
if(!f) u->next[c]->fail = root;
else u->next[c]->fail = f->next[c];
u->next[c]->val |= u->next[c]->fail->val;//状态合并,根据具体题意,不能用于统计
q.push(u->next[c]);
}
else if(u == root) u->next[c] = root;
else u->next[c] = u->fail->next[c];
}
}
}
int match(char *s) {
Trie *rt = root;
int len = strlen(s), ret = 0;
for(int i = 0; i < len; i++) {
int c = idx[s[i]+0];
rt = rt->next[c];
Trie *p = rt;
while(p && p->val) {
ret += p->val;
//p->val = 0;统计的时候要清零
p = p->fail;
}
}
return ret;
}
};
void haxi()
{
for(int i = 0; i < 26; i++)
idx['a'+i] = i;
}
int main()
{
haxi();
int T, m;
char str[M];
scanf("%d", &T);
while(T--) {
ac_auto ac;
scanf("%d", &m);
while(m--) {
scanf("%s", str);
ac.insert(str);
}
ac.get_f();
scanf("%s", str);
int ans = ac.match(str);
printf("%d\n", ans);
}
return 0;
}