trie图实际上是优化的一种AC自动机。
trie图是在trie树上加一些失配指针,实际上是类似KMP的一种字符串匹配算法。
失配指针类似KMP的nx数组,有效地利用了之前失配的信息,优化了时间复杂度。
比如trie树上的abc那个节点,失配后会指向bc。
所以我们需要知道上一层节点的fail指针,来求出这一层的fail指针。
那就~BFS吧~
懒得写了,大佬们讲的都比我好。
哪天有空了,可能会再详细写一写吧,补两张图什么的。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 7 int n,sz; 8 int s[1000005][30]; 9 int ed[1000005]; 10 int fal[1000005]; 11 char str[1000005]; 12 13 void ins(char *a) 14 { 15 int l=strlen(a+1); 16 int p=0; 17 for(int i=1;i<=l;i++) 18 { 19 int c=a[i]-'a'+1; 20 if(!s[p][c])s[p][c]=++sz; 21 p=s[p][c]; 22 } 23 ed[p]++; 24 } 25 26 queue<int>qq; 27 28 void build() 29 { 30 for(int i=1;i<=26;i++) 31 if(s[0][i])qq.push(s[0][i]); 32 while(!qq.empty()) 33 { 34 int p=qq.front(); 35 qq.pop(); 36 for(int i=1;i<=26;i++) 37 { 38 if(s[p][i])fal[s[p][i]]=s[fal[p]][i],qq.push(s[p][i]); 39 else s[p][i]=s[fal[p]][i]; 40 } 41 } 42 } 43 44 int cal(char *a) 45 { 46 int l=strlen(a+1); 47 int p=0,ans=0; 48 for(int i=1;i<=l;i++) 49 { 50 int c=a[i]-'a'+1; 51 p=s[p][c]; 52 for(int j=p;j&&~ed[j];j=fal[j]) 53 { 54 ans+=ed[j]; 55 ed[j]=-1; 56 } 57 } 58 return ans; 59 } 60 61 int main() 62 { 63 scanf("%d",&n); 64 char str[1000005]; 65 for(int i=1;i<=n;i++) 66 { 67 scanf("%s",str+1); 68 ins(str); 69 } 70 build(); 71 scanf("%s",str+1); 72 int ans=cal(str); 73 printf("%d",ans); 74 return 0; 75 }