【模板】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;

这难度算简单版???我已经不想做加强版了

所以可以简单的理解为将KMP放在Trie树上。

注意如果每次跳fail边复杂度过高,一次存储完可以进行优化。

这样的AC自动机就成为了Trie图。

不懂Trie图的自行百度(我也是自学了40分钟才搞懂,感觉整个人要炸了)

友情链接:https://www.cnblogs.com/cmmdc/p/7337611.html

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,ch[5000005][30];

int t,f[5000005],next[5000005];

char s[1000005];

inline void add(){
    int len=strlen(s+1),hhh=1;
    for(int i=1;i<=len;i++){
        int u=s[i]-'a';
        if(!ch[hhh][u]){
            ch[hhh][u]=++t;
        }
        hhh=ch[hhh][u];
    }
    f[hhh]++;
}
queue<int>q;

inline void getnext(){
    for(int i=0;i<26;i++)ch[0][i]=1;
    next[1]=0;
    q.push(1);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            int u=ch[x][i];
            if(!u){
                ch[x][i]=ch[next[x]][i];
            }
            else{
                int p=next[x];
                q.push(u);
                next[u]=ch[p][i];
            }
        }
    }
}

inline int find(){
    int len=strlen(s+1);
    int i=1,hhh=1,q,w,ans=0;
    while(i<=len){
        q=s[i]-'a';
        w=ch[hhh][q];
        while(w>1){
            if(f[w]==-1){
                break;
            }
            ans+=f[w];
            f[w]=-1;
            w=next[w];
        }
        hhh=ch[hhh][q];
        i++;
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    t=1;
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        add();
    }
    getnext();
    scanf("%s",s+1);
    printf("%d
",find());
    return 0;
} 
原文地址:https://www.cnblogs.com/hrj1/p/11135456.html