1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #define N 26 //表示子节点的个数,最多是26个
5 struct node //定义一个队列,等一会建立失效函数的时候会用到!! 因为是BFS广度优先遍历吗! 即一层一层的!!
6 {
7 node *fail; //失效指针,用于当前字符失配时,下一待匹配字符的位置
8 node *next[N]; //子节点
9 int end;
10 node() //构造函数,与C++中类里的构造函数一样一样的,就是用于初始化变量的!!
11 {
12 fail=NULL;
13 end=0;
14 memset(next,0,sizeof(next));
15 }
16 }*q[500001];//直接开成这么大的数组,方便操作50*10000
17 char key[51]; //存放关键词
18 char str[1000001];//存放模式串
19 int head,tail; //队列的首位指针
20 void build(char *str,node *root) //创建字典树
21 {
22 node *p=root;
23 int i=0,index;
24 while(str[i])
25 {
26 index=str[i]-'a';
27 if(p->next[index]==NULL) p->next[index]=new node();
28 p=p->next[index];
29 i++;
30 }
31 p->end++; //count==1表示次字符是该关键词的最末尾,这一点很重要
32 }
33 void buildAcAutomation(node *root) //建立失效函数,AC状态转化机
34 {
35 int i;
36 root->fail=NULL; //根节点的失效指针赋空,在50行有所体现
37 q[tail++]=root; //根节点入队
38 while(head!=tail) //当队列为空时,循环结束
39 {
40 node *temp=q[head++]; //队头元素出队
41 node *p=NULL;
42 for(i=0;i<N;i++) //26个单词依次查找是否存在
43 {
44 if(temp->next[i]!=NULL) //含有该子节点
45 {
46 if(temp==root) temp->next[i]->fail=root;//根节点的子节点毋庸置疑,失效指针指向root
47 else //其他情况判定子节点与其父节点的失效指针所指节点的子节点是否相同,
48 //如果相同,则指向它,否则同样指向根节点
49 {
50 p=temp->fail;
51 while(p!=NULL)
52 {
53 if(p->next[i]!=NULL)
54 {
55 temp->next[i]->fail=p->next[i];
56 break;
57 }
58 p=p->fail;
59 }
60 if(p==NULL) temp->next[i]->fail=root;
61 }
62 q[tail++]=temp->next[i]; //把其子节点入队
63 }
64 }
65 }
66 }
67 int query(node *root) //查询匹配单词的个数
68 {
69 int i=0,cnt=0,index;
70 node *p=root;
71 while(str[i])
72 {
73 index=str[i]-'a';
74 while(p->next[index]==NULL && p!=root) p=p->fail; //查找到一个单词的结尾,需转向失效函数所指处
75 p=p->next[index];
76 p=(p==NULL)?root:p; //如果不存在,则跳到根节点,重新从头匹配下一字符
77 node *temp=p;
78 while(temp!=root && temp->end!=-1) //到根节点说明本次查找结束
79 {
80 cnt+=temp->end; //cnt计数
81 temp->end=-1; //count==-1标记已经访问过,不再访问
82 temp=temp->fail;
83 }
84 i++;
85 }
86 return cnt;
87 }
88 int main()
89 {
90 int n,t;
91 scanf("%d",&t);
92 while(t--)
93 {
94 head=tail=0;
95 node *root=new node();
96 scanf("%d",&n);
97 while(n--)
98 {
99 scanf("%s",key);
100 build(key,root);
101 }
102 buildAcAutomation(root);
103 scanf("%s",str);
104 printf("%d\n",query(root));
105 }
106 return 0;
107 }
108 //研究了好长时间,终于想通了!刚开始感觉很复杂,其实把算法思想看明白了,代码就很容易理解了!