ac自动机,不详细,好理解

详细的解答这里不再赘述,推荐两篇博文,

https://www.cnblogs.com/hyfhaha/p/10802604.html;

https://blog.csdn.net/wyxeainn/article/details/77430218?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6;

这里略微分析一下我对前缀数组的认识和性质 

//定理 1:对于每一条树链如果fial[level1[k1]]=fial[level2[k2]],k1<k2,则存在0~k1,fial[level[i]]=fial[level2[k2-k1+i]]总成立
 //性质2:fail路径直达定理,如果fail[level]指向的是一个本来不存在的地址,trie[][i]存在可能最大的地址;
//匹配失败:如果文章匹配到某一条树链的level[t],下一个要查询的是index+'a,然而trie[level[t]][index]不存在我们就定义失败,扫描的指针指向fail
// fail 指针的作用:当前的树链是否可能是别的树链答案,已经是别的树链的答案。我们通过fail遍历所有以当前字母结尾的前缀中是否有答案;

 1 #include<iostream>
 2 #include<string>
 3 #include<queue>
 4 #include<cstring>
 5 using namespace std;
 6 const int MAX_=1e5;
 7 int trie[MAX_][26]={0};
 8 int wordti[MAX_]={0};//功能数组; 
 9 int fail[MAX_]={0};
10 int cnt=0;
11 void insert(string x)
12 {
13     int len=x.size(),p=0;
14     for(int i=0;i<len;i++)
15     {
16         int index=x[i]-'a';
17         if(trie[p][index]!=0)
18             trie[p][index]=++cnt;
19         p=trie[p][index];
20     }
21     wordti[p]++;
22  } 
23  //定理 1:对于每一条树链如果fial[level1[k1]]=fial[level2[k2]],k1<k2,则存在0~k1,fial[level[i]]=fial[level2[k2-k1+i]]总成立
24  //性质2:fail路径直达定理,如果fail[level]指向的是一个本来不存在的地址,trie[][i]存在可能最大的地址; 
25 //匹配失败:如果文章匹配到某一条树链的level[t],下一个要查询的是index+'a,然而trie[level[t]][index]不存在我们就定义失败,扫描的指针指向fail 
26 // fail 指针的作用:当前的树链是否可能是别的树链答案,已经是别的树链的答案。我们通过fail遍历所有以当前字母结尾的前缀中是否有答案; 
27  void getfail()
28  {
29      queue<int >que;
30      for(int i=0;i<26;i++)
31          if(trie[0][i]!=0){
32              fail[trie[0][i]]=0;
33              que.push(trie[0][i]);
34         } 
35     while(!que.empty()){
36         int now=que.front();
37         que.pop();
38         for(int i=0;i<26;i++){
39             if(trie[now][i]!=0){
40                 fail[trie[now][i]]=trie[fail[now]][i];//祖先继承法;特征我们数通过记忆化搜索,或者等于它已经记录的数据实现的 
41                 que.push(trie[now][i]); 
42             }
43             else
44                 trie[now][i]=trie[fail[now]][i];//我们只要研究如果当前节点存在,就往下搜索,如果这个指针不存在,我们通过fail直接到达可行的下表 
45         }
46     }
47  }
48  
49 void query(char *s)
50 {
51     int u=0,len=strlen(s);
52     for(int i=0;i<len;i++){
53         int index=s[i]-'a';
54         u=trie[u][index]; 
55         //功能区 ,寻找以当前字母结尾是否存在已经匹配成功的模式窜 
56         int k=u;
57         while(k>0){
58             if(wordti[k]>0) ans++;
59             k=fail[k];
60         } 
61     } 
62 } 
原文地址:https://www.cnblogs.com/hjw201983290498/p/12783568.html