HDU 2222 Keywords Search
题面见链接。
题解:
第一次学 AC 自动机,感觉差不多掌握基础了吧。
这是一道入门模板题。就是给定文本串,和一些模式串,求模式串在文本串出现的个数。
AC自动机主要步骤:
1、先建一棵 trie 树,然后记录该点是否为某模式串的最后一位节点,且以这一个节点结尾的模式串的个数。
2、预处理 fail 指针。 x 的 fail 指针连的是 fa[x] 的 fail 的 nxt 。目的是为了保证 fail 指针连的节点的模式串是 以 x 结尾的模式串的后缀。这样才能统计答案。
3、开始 AC 自动机主过程:从根节点开始按照文本串一位一位往下匹配。找到一个节点就检查他的 fail 节点是否能够加入答案,如果可以则加入答案,并标记为“已搜过”,下次就不用再搜一遍,提高时间效率。
贴代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=500005; 4 int t,n,rt,tot,q[N]; 5 struct node{ 6 int nxt[26]; 7 int sum,fail; 8 }e[N]; 9 char s[N<<1]; 10 inline void insert(char *s) 11 { 12 rt=0; 13 for (int i=0; s[i]; i++) 14 { 15 if (!e[rt].nxt[s[i]-'a']) 16 e[rt].nxt[s[i]-'a']=++tot; 17 rt=e[rt].nxt[s[i]-'a']; 18 } 19 e[rt].sum++; 20 } 21 inline void getfail() 22 { 23 int head=0,tail=1; 24 q[1]=0; 25 while (head<tail) 26 { 27 int x=q[++head]; 28 for (int i=0; i<26; i++) 29 { 30 if (int y=e[x].nxt[i]) 31 { 32 if (x==0) e[y].fail=0; 33 else { 34 int tmp=e[x].fail; 35 while (tmp && e[tmp].nxt[i]==0) 36 tmp=e[tmp].fail; 37 e[y].fail=e[tmp].nxt[i]; 38 } 39 q[++tail]=y; 40 } 41 } 42 } 43 } 44 inline int acmatch(char *s) 45 { 46 getfail(); 47 rt=0; 48 int cnt=0; 49 for (int i=0; s[i]; i++) 50 { 51 while (rt && e[rt].nxt[s[i]-'a']==0) 52 rt=e[rt].fail; 53 int y=rt=e[rt].nxt[s[i]-'a']; 54 while (y && ~e[y].sum) 55 { 56 cnt+=e[y].sum; 57 e[y].sum=-1; 58 y=e[y].fail; 59 } 60 } 61 return cnt; 62 } 63 int main() 64 { 65 scanf("%d",&t); 66 while (t--) 67 { 68 memset(e,0,sizeof(e)); tot=0; 69 scanf("%d",&n); 70 for (int i=1; i<=n; i++) 71 { 72 scanf("%s",s); 73 insert(s); 74 } 75 scanf("%s",s); 76 printf("%d ",acmatch(s)); 77 } 78 return 0; 79 }
加油加油加油!!!fighting fighting fighting!!!