1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<queue>
5 #define maxn 5000000+10
6 using namespace std;
7 char str[maxn*2];
8 struct node{
9 int fail;//失配指针;
10 int cnt;//单词出现的次数;
11 int next[62];// 此节点的下一个(儿子)节点;
12 }trie[maxn];//节点结构体;
13 int k=0,ans=0;
14 queue<int> q;//队列:建失配指针使用;
15 void build_trie(int id,char *s)//id表示第几个结点,即所有字符串从第0个节点开始向下建;*s即表示这个字符串;
16 {
17 int len=strlen(s);//该字符串的长度;(相当于字符串最后一个字符的深度)
18 int j=0;
19 for(int i=0;i<len;i++){
20 j=s[i]-'a';
21 if(trie[id].next[j]==0)/*若此字母未出现在当前位置的下一深度*/
22 {
23 trie[id].next[j]=++k;//当前节点对于j字母节点的位置;即j字母的节点序号;
24 }
25 id=trie[id].next[j];//id传为下一字母的地址;
26 }
27 trie[id].cnt++;//对此单词的数量++;
28 }
29 void build_fail(int id)
30 {
31 while(!q.empty()) q.pop();//为了放心,(be afraid of队列未清空)
32 for(int i=0;i<26;i++)//遍历超级节点下的26个字母;
33 {
34 int j=trie[id].next[i];
35 if(j!=0){
36 q.push(j);
37 trie[j].fail=id;//第一层的节点失配指针皆指向超级节点;
38 }
39 }
40 while(!q.empty())
41 {
42 int now=q.front();q.pop();//取出当前位置;(队首元素)
43 for(int i=0;i<26;i++)
44 {
45 int j=trie[now].next[i];
46 if(j==0)//当前位置下没有这个节点;就调到它失配指针所指向的节点下的此个字母节点;
47 {
48 trie[now].next[i]=trie[trie[now].fail].next[i];//若为0,不影响,指向超级节点;
49 continue;//该点遍历完成,直接进入下一节点的遍历;
50 }
51 trie[j].fail=trie[trie[now].fail].next[i];//如果当前位置下有这个字母节点,则其失配指针指向当前位置的失配指针下的该节点;
52 //若当前位置的失配指针下没有当前遍历的该字母节点,任不影响(为0,指向超级节点);
53 q.push(j);//存入数组;
54 }
55 }
56 }
57 void solve_trie(int id,char *s)//查询函数;
58 {
59 int len=strlen(s),j=0;
60 for(int i=0;i<len;i++)
61 {
62 int j=trie[id].next[s[i]-'a'];//当前位置的下一个节点位置;
63 while(j && trie[j].cnt!=-1)//当此节点存在同时其cnt未被遍历;
64 {
65 ans+=trie[j].cnt;//将答案加上所搜索的字符串中所包含的该单词数 ;
66 trie[j].cnt=-1;//标记(因为是看有多少个模式串出现过,而不是出现多少次)
67 j=trie[j].fail;//直接将位置指向其失配指针的位置(节约时间)(也就是找匹配了的模式串的fail)(就是删除模式串前面的一部分的模式串)
68 //一个fail就是把匹配的串的前面一部分删去,而建立的字典树是模式串
69 }
70 id=trie[id].next[s[i]-'a'];//id继承,当前位置的下一个节点; 0也没关系
71 }
72 }
73 int main()
74 {
75 int n;
76 scanf("%d",&n);
77 for(int i=1;i<=n;i++)
78 {
79 scanf("%s",str);//第i个短字符串;
80 build_trie(0,str);//0为超级根节点(即所有字符串的共同祖先);(即从0开始建)
81 }//字典树建立完成;
82 build_fail(0);//建失配指针;
83 scanf("%s",str);//输入需查询的字符串;
84 solve_trie(0,str); //查询;
85 printf("%d\n",ans);//输出;
86 return 0;
87 }
88 //https://www.luogu.org/problemnew/solution/P3808
89 //还有最好用gets