题目大意:给定一些单词和一个字符串,求有多少单词在字符串中出现过
首先我不想吐槽题号。真的不想。真的不想!!别问我为什么说这句话!!不想就是了!!
AC自动机模板题
简单介绍一下AC自动机
首先不要把这东西和自动AC机弄混 自动AC机算法等我们发明之后再加介绍
这东西的实现方法就是把所有单词插入一棵Trie树 然后在Trie树上跑KMP算法
每个节点有一个next指针 和KMP算法中的next一样 指向最长公共前后缀所代表的节点上 不存在指向root
匹配的时候每匹配到一个节点时,将该节点、该节点的next节点、该节点的next节点的next节点……直到root为止的单词数全都加到ans上,然后清零(防止重复计数)
具体见 http://blog.csdn.net/niushuai666/article/details/7002823
这题卡内存,开动态的不用想了,开静态的可以考虑将内存恰好压到32768KB,我卡了32132KB过去的。。。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct Trie{
char letter;
int next,fa;
int cnt;
int sons[26];
}tree[260200];
int tot,root;
char s[1001001];
int n,ans;
void insert(int &p,char *pos,int from)
{
int num=(*pos)-'a';
if(!p)
{
p=++tot;
tree[p].fa=from;
tree[p].letter=*(pos-1);
}
if(!*pos)
{
tree[p].cnt++;
return ;
}
insert(tree[p].sons[num],pos+1,p);
}
int q[65540];
unsigned short r,h;
void bfs()
{
int i,temp;
q[++r]=root;
while(r!=h)
{
int p=q[++h];
if(tree[p].fa==root)
tree[p].next=root;
else
{
temp=tree[tree[p].fa].next;
while( temp!=root && !tree[temp].sons[tree[p].letter-'a'] )
temp=tree[temp].next;
if( tree[temp].sons[tree[p].letter-'a'] )
temp=tree[temp].sons[tree[p].letter-'a'];
tree[p].next=temp;
}
for(i=0;i<26;i++)
if(tree[p].sons[i])
q[++r]=tree[p].sons[i];
}
}
void Aho_Corasick_Automation(int p,char *pos)
{
int temp;
for(;*pos;pos++)
{
while( p!=root && !tree[p].sons[(*pos)-'a'] )
p=tree[p].next;
if(tree[p].sons[(*pos)-'a'])
{
p=tree[p].sons[(*pos)-'a'];
for(temp=p;temp!=root;temp=tree[temp].next)
ans+=tree[temp].cnt,tree[temp].cnt=0; }
}
}
void initialize()
{
memset(tree,0,sizeof tree);
root=tot=ans=0;
}
int main()
{
int i,T;
for(cin>>T;T;T--)
{
initialize();
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%s",s+1);
insert(root,s+1,1);
}
bfs();
scanf("%s",s+1);
Aho_Corasick_Automation(root,s+1);
cout<<ans<<endl;
}
}