学习AC自动机请戳这里:大神blog........
自动机的模板:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 100005
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std; struct trie {
trie *fail; //失败指针
trie *next[26];
int cnt;
trie () {
fail = 0;cnt = 0;
memset(next,0,sizeof(next));
}
}*q[511111]; //模拟队列
trie *rt;
int head,tail;
char keyword[51];
char book[1111111]; void insert(char *key) {
trie *p = rt;
int t;
while(*key) {
t = *key - 'a';
if(p->next[t] == NULL) p->next[t] = new trie();
p = p->next[t];
key++;
}
p->cnt++; //表示一个单词
} void bfs() {
rt->fail = NULL; //根结点fail指向空
q[head++] = rt;
while(head != tail) {
trie *t = q[tail++];
trie *p = NULL;
for(int i=0; i<26; i++) {
if(t->next[i] != NULL) { //对所有儿子的fail指针匹配并且入队
if(t == rt) t ->next[i]->fail = rt; //如果刚从根节点出发
else { //否则沿着他父亲的失败指针走,
//直到走到一个节点,他的儿子中也有相同字符的节点。然后把当前节点的失败指针指向他的那个儿子
p = t->fail;
while(p != NULL) {
if(p->next[i] != NULL) {
t->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if(p == NULL) t->next[i]->fail = rt; //如果一直走到了root都没找到,那就把失败指针指向root
}
q[head++] = t->next[i];
}
}
}
} int query(char *key) {
trie *p = rt;
int cnt = 0;
while(*key) {
int t = *key - 'a';
while(p->next[t] == NULL && p != rt) p = p->fail; //如果当前字符不匹配
p = p->next[t];
if(p == NULL) p = rt; //最终还是未匹配
trie *tmp = p;
while(tmp != rt && tmp->cnt != -1) {
cnt += tmp->cnt;
tmp->cnt = -1; //该处已经出现过了
tmp = tmp->fail;
}
key++;
}
return cnt;
}
int main(){
int T;
cin >> T;
while(T --) {
rt = new trie();
int n;
cin >> n;
for(int i=0; i<n; i++) {
scanf("%s",keyword);
insert(keyword);
}
head = 0; tail = 0;
bfs();
scanf("%s",book);
printf("%d\n",query(book));
}
return 0;
}