AC自动机(Keywords Search)
题目链接:https://cn.vjudge.net/contest/280743#problem/A
题目大意:首先给你T组测试样例,然后给你n个字符串,最后再给你一个模式串,然后问你这一些字符串中是模式串的子串的有多少个?
具体思路:AC自动机模板题,先说一下各个数组的作用吧,ch数组是字典树中的数组,val也是字典树中的数组,储存的是从根节点到当前这个节点是不是有字符串。fail和last就是AC自动机中的数组了,fail数组的作用就是从根节点到当的节点形成的字符串的后缀是一个新的路径的前缀,能够在匹配失败的时候,通过指针的跳动来节省时间。last数组的作用就是在求和的时候方便记录,如果当前节点有字符串的话,直接通过指针的跳动能够避免当前节点没有字符串的情况。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<stdio.h> 4 #include<cstring> 5 #include<string> 6 #include<cmath> 7 #include<queue> 8 #include<algorithm> 9 using namespace std; 10 # define ll long long 11 const int maxn = 2e5+50000; 12 const int maxm = 1e6+100; 13 char str[maxm]; 14 int tot,ch[maxn][30],val[maxn]; 15 int fail[maxn],last[maxn]; 16 void add() 17 { 18 int p=0; 19 int len=strlen(str); 20 for(int i=0; i<len; i++) 21 { 22 int u=str[i]-'a'; 23 if(!ch[p][u]) 24 ch[p][u]=++tot; 25 p=ch[p][u]; 26 } 27 val[p]++; 28 } 29 void getfail() 30 { 31 queue<int>q; 32 for(int i=0; i<26; i++) 33 { 34 if(ch[0][i]) 35 q.push(ch[0][i]); 36 } 37 while(!q.empty()) 38 { 39 int top=q.front(); 40 q.pop(); 41 for(int i=0; i<26; i++) 42 { 43 int u=ch[top][i]; 44 if(u==0) 45 continue; 46 q.push(u); 47 int v=fail[top]; 48 while(v&&ch[v][i]==0) 49 v=fail[v]; 50 fail[u]=ch[v][i]; 51 last[u]=val[fail[u]] ? fail[u] : last[fail[u]]; 52 } 53 } 54 } 55 int cal(int t) 56 { 57 int ans=0; 58 while(t) 59 { 60 ans+=val[t]; 61 val[t]=0; 62 t=last[t]; 63 } 64 return ans; 65 } 66 int getans() 67 { 68 int ans=0; 69 int len=strlen(str); 70 int p=0; 71 for(int i=0; i<len; i++) 72 { 73 int u=str[i]-'a'; 74 while(p&&ch[p][u]==0) 75 p=fail[p]; 76 p=ch[p][u]; 77 if(val[p]) 78 ans+=cal(p); 79 else if(fail[p]) 80 ans+=cal(fail[p]); 81 } 82 return ans; 83 } 84 void init() 85 { 86 for(int i=0; i<tot; i++) 87 { 88 fail[i]=0,last[i]=0,val[i]=0; 89 for(int j=0; j<30; j++) 90 { 91 ch[i][j]=0; 92 } 93 } 94 tot=0; 95 } 96 int main() 97 { 98 int T; 99 scanf("%d",&T); 100 while(T--) 101 { 102 init(); 103 int n; 104 scanf("%d",&n); 105 for(int i=1; i<=n; i++) 106 { 107 scanf("%s",str); 108 add(); 109 } 110 getfail(); 111 scanf("%s",str); 112 int ans=getans(); 113 printf("%d\n",ans); 114 } 115 return 0; 116 }