小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
Input
第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1―50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
Output
按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
分析:AC自动机的题目。AC自动机的题目,其时间复杂度和题目有关系。如果在找到某个匹配点后还需要沿fail指针往上遍历到根,则时间复杂度就为O(S*H)。其中M为trie的高度。如果不需要沿fail遍历到根,则时间复杂度为O(H*N+S)。
AC自动机在实现时,可以将nxt指针全部利用起来。trie[r].nxt[i]如果等于0,则将trie[r].nxt[i]=trie[trie[r].fail].nxt[i]。速度可以稍微快一点。
#include<iostream> #include<cstdio> #include<cstring> #define MAXC 26 #define MAXS 1002 #define MAXN 2000005 #define MAXL 51 char word[MAXS][MAXL],web[MAXN]; struct node { int nxt[MAXC],fail,id; void clear() { memset(nxt,0,sizeof nxt); fail=0,id=0; } }trie[MAXL*MAXS]; int myq[MAXL*MAXS],head,tail,root,tot=1,ans[MAXS],n; void insert(int r,char *s,int id) { int len=strlen(s); for(int i=0;i<len;i++) { if(trie[r].nxt[s[i]-‘A‘]==0) {trie[r].nxt[s[i]-‘A‘]=++tot; trie[tot].clear(); } r=trie[r].nxt[s[i]-‘A‘]; } trie[r].id=id; } void build(int r) { trie[r].fail=r; myq[tail++]=r; int ch; while(head<tail) { r=myq[head++]; if(r==root) { for(int i=0;i<MAXC;i++) { if(trie[r].nxt[i]==0) trie[r].nxt[i]=root; else {myq[tail++]=trie[r].nxt[i]; trie[trie[r].nxt[i]].fail=root; } } } else { for(int i=0;i<MAXC;i++) { ch=trie[r].nxt[i]; if(ch) { myq[tail++]=ch; if(trie[trie[r].fail].nxt[i]!=ch) trie[ch].fail=trie[trie[r].fail].nxt[i]; else trie[ch].fail=root; } else trie[r].nxt[i]=trie[trie[r].fail].nxt[i]; } } } } void query(int r,char *s) { int len=strlen(s),failp,val; for(int i=0;i<len;i++) { val=s[i]-‘A‘; if(val<0||val>25) {r=root;continue;} r=trie[r].nxt[val]; for(failp=r;failp!=root;failp=trie[failp].fail) if(trie[failp].id) ans[trie[failp].id]++; } } int main() { while(~scanf("%d",&n)) { root=1;tot=1; head=tail=0; memset(ans,0,sizeof ans); trie[root].clear(); for(int i=0;i<n;i++) { scanf("%s",word[i]); insert(root,word[i],i+1); } build(root); scanf("%s",web); query(root,web); for(int i=1;i<=n;i++) { if(ans[i]) printf("%s: %d\n",word[i-1],ans[i]); } } }
时间: 2024-10-06 22:01:16