差不多是赤果果的AC自动机吧~~只是题目很恶心的是..所给的keyword可能有相同的..所以处理的时候注意下..还有..开始我还是超时的...原因..若当前点前面各种方式访问过..那么就没必要再来找他或者说找他的fail来看有无keyword了...以前一直没注意..这道题提醒了这一点...省去很多无谓搜索..从TLE到了250MS...
其实这两天时在整一道AC自动机DP的...NotOnlySucuss那博客里对那题的说明就是一行"水题..大数"..我是做了好久也没对..AC自动机DP的感觉还没来...
Program:
#include<iostream> #include<queue> #include<string.h> #include<stdio.h> using namespace std; struct node { int w,fail,son[27]; }T[500005]; int t,n,i,l,m,h,k,ans; char s[1000005]; bool used[500005]; queue<int> myqueue; int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d",&t); while (t--) { scanf("%d",&n); memset(T[0].son,0,sizeof(T[0].son)); T[0].w=T[0].fail=0; m=0; while (n--) { scanf("%s",s); h=0; l=strlen(s); for (i=0;i<l;i++) { k=s[i]-'a'; if (!T[h].son[k]) { T[h].son[k]=++m; memset(T[m].son,0,sizeof(T[m].son)); T[m].w=T[m].fail=0; } h=T[h].son[k]; } T[h].w++; } while (!myqueue.empty()) myqueue.pop(); for (i=0;i<26;i++) if (T[0].son[i]) myqueue.push(T[0].son[i]); while (!myqueue.empty()) { h=myqueue.front(); myqueue.pop(); for (i=0;i<26;i++) if (T[h].son[i]) { myqueue.push(T[h].son[i]); k=T[h].fail; while (k && !T[k].son[i]) k=T[k].fail; T[T[h].son[i]].fail=T[k].son[i]; } } scanf("%s",s); l=strlen(s); memset(used,false,sizeof(used)); used[0]=true; h=ans=0; for (i=0;i<l;i++) { k=s[i]-'a'; while (h && !T[h].son[k]) h=T[h].fail; h=T[h].son[k]; k=h; while (k && !used[k]) { if (T[k].w) ans+=T[k].w; used[k]=true; k=T[k].fail; } } printf("%d\n",ans); } return 0; }