不要问我为什么刚写这个东西。
AC自动机=trie+KMP
【说实话KMP我都不太会写】
(Goes型备注版代码最适合G.S.M.学习了)
AC自动机模板:
简单版:(洛谷P3808)
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#if 0
Writers: G.S.M. && Goes
#endif
struct ss{
int fail,vis[27],end;
//fail指针 该点的儿子有没有i 以该点做结尾的模串的个数
}AC[1000005];
int cnt=0;//trie的指针
inline void build(string s){
int len=s.length();int now=0;
for(int i=0;i<len;i++){
if(!AC[now].vis[s[i]-'a'])//如果没有这个子节点
AC[now].vis[s[i]-'a']=++cnt;//就把它构造出来
now=AC[now].vis[s[i]-'a'];//向下构造
}AC[now].end+=1;
return ;//一串一串地往里面加
}
inline void Get_fail(){
queue < int > Q ;
for ( int i = 0 ; i < 26 ; i ++ )
if( AC[0].vis[i] ) {//单独处理 第二层的fail指针
AC[AC[0].vis[i]].fail=0;
Q.push(AC[0].vis[i]);
}
while(!Q.empty()){
int pos=Q.front();Q.pop();
for(int i=0;i<26;i++)//枚举所有字母
if( AC[pos].vis[i] ){//如果存在该子节点
AC[ AC[pos].vis[i] ].fail
= AC[ AC[pos].fail ].vis[i];
Q.push(AC[pos].vis[i]);
}
else AC[pos].vis[i]=AC[AC[pos].fail].vis[i];
}
}
inline int query(string s){//求解
int len=s.length();int now=0,ans=0;
for(int i=0;i<len;i++){
now=AC[now].vis[s[i]-'a'];
for(int t=now;t&&AC[t].end!=-1;t=AC[t].fail)
ans+=AC[t].end,AC[t].end=-1;
}return ans;
}
int main()
{
int n;string s;cin>>n;
for(int i=1;i<=n;i++){
cin>>s;build(s);
}//构造字典树trie
AC[0].fail=0;Get_fail();
//fail指针(类似KMP的nex指针)
cin>>s;printf("%d\n",query(s));
return 0;
}