找到模式串在文本串中出现的个数(洛谷p3796)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct tree{
int fail;
int vis[26];
int num;
}ac[1000005];//所有模式串构成的字典树
int cnt=0;
void build(string str)//构建字典树
{
int sz=str.length(),now=0;
for(int i=0;i<sz;i++){
if(ac[now].vis[str[i]-'a']==0)
ac[now].vis[str[i]-'a']=++cnt;
now=ac[now].vis[str[i]-'a'];
}
ac[now].num++;
}
void get_fail()//配失配指针
{
queue<int> ac_q;
for(int i=0;i<26;i++){ //第二层的失配指针都为0
if(ac[0].vis[i]!=0){
ac[ac[0].vis[i]].fail=0;
ac_q.push(ac[0].vis[i]);
}
}
while(!ac_q.empty())
{
int u=ac_q.front();
ac_q.pop();
for(int i=0;i<26;i++){
if(ac[u].vis[i]!=0){
ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];//点失配指针指向->父亲的失配指向的点 的 相同儿子
ac_q.push(ac[u].vis[i]);
}
else ac[u].vis[i]=ac[ac[u].fail].vis[i];//失配指向
}
}
}
int get_ans(string str)//模式串在文本串中出现的个数
{
int sz=str.length(),now=0,ans=0;
for(int i=0;i<sz;i++){
now=ac[now].vis[str[i]-'a'];
for(int j=now;j&&ac[j].num!=-1;j=ac[j].fail) //不断失配寻找适配
ans+=ac[j].num,ac[j].num=-1;
}
return ans;
}
int main()
{
int n;
string str;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>str;
build(str);
}//n个模式串
ac[0].fail=0;
get_fail();//配失配、
cin>>str;
cout<<get_ans(str)<<endl;
return 0;
}