http://www.elijahqi.win/archives/3227
题目背景
这是一道简单的AC自动机模板题。
用于检测正确性以及算法常数。
为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。
管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意
题目描述
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入输出格式
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案
输入输出样例
输入样例#1: 复制
2
a
aa
aa
输出样例#1: 复制
2
说明
subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;
subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;
建出AC自动机 然后将文本串在ACM上跑 统计答案的时候暴力跳fail表示求我这个点的后缀有多少是答案 但是因为fail树很多最后会汇流到一起而我们统计的是有几个出现所以统计之后要改成0
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;char s[N];
int cnt=1,n,sum[N],fail[N],trans[N][26];
inline void insert1(char *s){
static int p;p=1;
for (int i=1,nxt;s[i];++i){
if (!trans[p][s[i]-'a']) trans[p][s[i]-'a']=nxt=++cnt;
else nxt=trans[p][s[i]-'a'];p=nxt;
}++sum[p];
}
inline void buildAC(){
queue<int>q;q.push(1);for (int i=0;i<26;++i) trans[0][i]=1;
while(!q.empty()){
int x=q.front();q.pop();
for (int i=0;i<26;++i){
int &y=trans[x][i];
if (!y) {y=trans[fail[x]][i];continue;}
fail[y]=trans[fail[x]][i];q.push(y);
}
}
}
int main(){
freopen("luogu3808.in","r",stdin);
scanf("%d",&n);int ans=0;
for (int i=1;i<=n;++i) scanf("%s",s+1),insert1(s);
scanf("%s",s+1);int p=1;buildAC();
for (int i=1;s[i];++i){
p=trans[p][s[i]-'a'];
for (int j=p;j&&sum[j];j=fail[j]) ans+=sum[j],sum[j]=0;
}printf("%d\n",ans);
return 0;
}