AC自动机 模板

【模板】AC自动机(简单版)

题目背景

# 通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。 这是一道简单的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;
 
#include<queue>
#include<stdio.h>

const int N=1e6+5;
const int sz=26;
int T,n,ans,cnt=1,now,p,fail[N],tag[N],tr[N][sz];char s[N<<1];

#define son (s[i]-'a')
void insert(){
    now=1;
    for(int i=0;s[i];i++){
        if(!tr[now][son]) tr[now][son]=++cnt;
        now=tr[now][son];
    }
    tag[now]++;
}
std::queue<int>q;
void acmatch(){
    q.push(1);
    fail[1]=0;
    for(int i=0;i<sz;i++) tr[0][i]=1;
    while(!q.empty()){
        now=q.front();q.pop();
        for(int i=0;i<sz;i++){
            if(!tr[now][i]) continue;
            for(p=fail[now];p&&!tr[p][i];p=fail[p]);
            fail[tr[now][i]]=p?tr[p][i]:1;
            q.push(tr[now][i]);
        }
    }
}
void solve(){
    p=1;
    for(int i=0;s[i];i++){
        for(;p&&!tr[p][son];p=fail[p]);
        p=p?tr[p][son]:1;
        for(int j=p;j&&~tag[j];j=fail[j]){
            ans+=tag[j];
            tag[j]=-1;
        }
        // -1 break to faster
    }
    printf("%d
",ans);
}
#undef son

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%s",s),insert();
    acmatch();
    scanf("%s",s);
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/shenben/p/12675525.html