链接:点击打开链接
题意:给出一个字典和一个模式串,问模式串中出现几个字典中的单词
代码:
#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;
}