hdu2222(ac自己主动机)
链接:点击打开链接
题意:给出一个字典和一个模式串。问模式串中出现几个字典中的单词
代码:
#include <queue> #include <vector> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int siz=500005; struct node{ int c[26]; int dis,fail; }s[siz]; int rt; void in(char ss[]){ int i,u; u=0; for(i=0;ss[i];i++){ if(s[u].c[ss[i]-'a']==0) s[u].c[ss[i]-'a']=rt++; u=s[u].c[ss[i]-'a']; } s[u].dis++; //字典中可能有同样的单词 } void getfail(){ int u,v,i,j,tmp; queue<int> qu; qu.push(0); while(qu.size()){ u=qu.front(); qu.pop(); for(i=0;i<26;i++){ if(v=s[u].c[i]){ if(u==0) s[v].fail=0; else{ tmp=s[u].fail; while(tmp&&s[tmp].c[i]==0){ tmp=s[tmp].fail; } s[v].fail=s[tmp].c[i]; } qu.push(v); } } } } int ac(char ss[]){ int i,j,u,v,sum; u=sum=0; getfail(); for(i=0;ss[i];i++){ while(u&&s[u].c[ss[i]-'a']==0) u=s[u].fail; v=u=s[u].c[ss[i]-'a']; while(s[v].dis){ //每一个单词仅仅能被统计一次,所以 sum+=s[v].dis; //每一次fail需一直往回走,而且 s[v].dis=0; //路过的节点都清零,事实上由于这个 v=s[v].fail; //条件。复杂度比理论上来说要退化非常多啊.... } } return sum; } int main(){ //推荐看hiho一下第四周去学习ac自己主动机, int n,i,j,t; //博客上应该是没有比那个讲的更具体的 char ss[siz<<1]; scanf("%d",&t); while(t--){ scanf("%d",&n); rt=1; memset(s,0,sizeof(s)); for(i=1;i<=n;i++){ scanf("%s",ss); in(ss); } scanf("%s",ss); printf("%d\n",ac(ss)); } return 0; }