AC自动机例题

P3808 [模板]AC自动机(简单版)

[题目描述]

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=1e6+5;
const int MAXV=26;

namespace ACzdj{
    struct Trie{
        int v[MAXV];
        int fail,end;
    }AC[MAXN];
    int Ncnt;
    inline void build(string s){
        int cur=0,l=s.length();
        for(int i=0;i<l;i++){
            if(!AC[cur].v[s[i]-‘a‘])
                AC[cur].v[s[i]-‘a‘]=++Ncnt;
            cur=AC[cur].v[s[i]-‘a‘];
        }
        AC[cur].end+=1;
    }
    inline void Get_fail(){
        queue <int> q;
        for(int i=0;i<26;i++)
            if(AC[0].v[i]){
                AC[AC[0].v[i]].fail=0;
                q.push(AC[0].v[i]);
            }
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(AC[u].v[i]){
                    AC[AC[u].v[i]].fail=AC[AC[u].fail].v[i];
                    q.push(AC[u].v[i]);
                }
                else
                    AC[u].v[i]=AC[AC[u].fail].v[i];
            }
        }
    }
    inline int query(string s){
        int res=0;
        int l=s.length(),cur=0;
        for(int i=0;i<l;i++){
            cur=AC[cur].v[s[i]-‘a‘];
            for(int t=cur;t&&AC[t].end!=-1;t=AC[t].fail){
                res+=AC[t].end;
                AC[t].end=-1;
            }
        }
        return res;
    }
}using namespace ACzdj;

int n;
string s;

int main(){
    n=read();
    for(int i=1;i<=n;i++){
        cin>>s;
        build(s);
    }
    AC[0].fail=0;
    Get_fail();
    cin>>s;
    printf("%d\n",query(s));
}

P3796 [模板]AC自动机(加强版)

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=150000;
const int MAXM=155;
const int MAXV=26;

struct Node{
    int num,id;
    friend bool operator < (Node a,Node b){
        if(a.num==b.num) return a.id<b.id;
        return a.num>b.num;
    }
}ans[MAXM];

namespace ACzdj{
    struct Trie{
        int v[MAXV];
        int fail,end;
    }AC[MAXN];
    int Ncnt;
    inline void clear(int x){
        for (register int i = 0; i < 26; ++i)
            AC[x].v[i] = 0;
        AC[x].fail=0,AC[x].end=0;
    }
    inline void build(const string& s,int id){
        int cur=0,l=s.length();
        for(int i=0;i<l;i++){
            if(!AC[cur].v[s[i]-‘a‘]){
                AC[cur].v[s[i]-‘a‘]=++Ncnt;
                clear(Ncnt);
            }
            cur=AC[cur].v[s[i]-‘a‘];
        }
        AC[cur].end=id;
    }
    inline void Get_fail(){
        queue<int> q;
        for(int i=0;i<26;i++)
            if(AC[0].v[i]){
                AC[AC[0].v[i]].fail=0;
                q.push(AC[0].v[i]);
            }
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(AC[u].v[i]){
                    AC[AC[u].v[i]].fail=AC[AC[u].fail].v[i];
                    q.push(AC[u].v[i]);
                }
                else
                    AC[u].v[i]=AC[AC[u].fail].v[i];
            }
        }
    }
    inline void query(const string& s){
        int l=s.length(),cur=0;
        for(int i=0;i<l;i++){
            cur=AC[cur].v[s[i]-‘a‘];
            for(int t=cur;t;t=AC[t].fail)
                ans[AC[t].end].num++;
        }
    }
}using namespace ACzdj;

int n;
string s[MAXM];

int main(){
//  freopen("trie.in","r",stdin);
//  freopen("trie.out", "w", stdout);
    while(n = read()){
        clear(Ncnt=0);
        for(int i=1;i<=n;i++){
            cin>>s[i];
            ans[i].num=0,ans[i].id=i;
            build(s[i],i);
        }
        AC[0].fail=0;
        Get_fail();
        cin>>s[0];
        query(s[0]);
        sort(ans+1,ans+n+1);
        printf("%d\n",ans[1].num);
        cout<<s[ans[1].id]<<endl;
        for(int i=2;ans[i].num==ans[i-1].num&&i<=n;i++)
            //printf("%s\n",s[ans[i].id]);
            cout<<s[ans[i].id]<<endl;
    }
}

原文地址:https://www.cnblogs.com/lizehon/p/10390192.html

时间: 2024-11-09 23:50:52

AC自动机例题的相关文章

AC自动机【模板】+经典例题

AC自动机模板 经典例题 Keywords Search HDU - 2222 [求目标串中出现了几个模式串] [(注意:模式串可能会重复)] 模板: 1 const int maxn=26; 2 struct Trie 3 { 4 int next[500010][maxn]; 5 int fail[500010],end[500010]; 6 int root,L; 7 int newnode() //初始化 8 { 9 for(int i=0;i<26;i++) 10 next[L][i]

AC自动机入门和几道例题

一直被AC自动机这个名字唬住,以为很难,自动AC?其实不是.数模还有CA自动机(元胞自动机),听起来也怪吓人的,对ACM选手来说,算是一种模拟. AC自动机=字典树+KMP.字典树是必须要懂的:KMP主要了解一下回溯思想,问题不大. KMP解决的是一个母串和一个模式串的匹配问题. 字典树解决的是许多字符串的前缀和问题. AC自动机解决的是一个母串和许多模式串的匹配问题,把所有的模式串搞成一棵字典树,再用母串去字典树上跑. 引入失配指针的概念,对于当前遍历到的母串某个字符,在字典树中找不下去了,不

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

AC自动机算法详解

首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过.要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识.AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程.     如果你对KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干

浩爷AC自动机快速学习方案

    今天弄完自动机之后,从那天比赛的阴影中爬出来了,猛地一看真不咋滴难,仔细一看这尼玛还不如猛的一看...     必备算法:KMP,字典树(KMP我写了,字典树太简单,就是一个思想,我可以一个图教你做人)     先讲一下字典树:看图     好了,字典树就看酱紫一个图,你要是脑残就装不懂吧!!    下面是AC自动机的正题:     正如KMP中的求next函数是同样的一个原理     节点的属性:二十六个字母的指针,fail指针,其他...     重点:fail指针,我把它叫做同级指

AC自动机算法及模板

关于AC自动机 AC自动机:Aho-Corasickautomation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过.要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识.AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程. 简单来说,AC自动机是用来进行多模式匹配(单个主串,多个模式串)的高效算法. AC自动机的构造过程 使用Aho-

[知识点]Trie树和AC自动机

// 此博文为迁移而来,写于2015年5月27日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w1s8.html 1.前言 怪我咯,因为Trie树和AC自动机的密切相关,我想一起讲完哈哈...看过前面博文的同学应该都知道了,AC自动机其实就是相当于在Trie树上跑KMP. 2.Trie树 Trie树,就是字母树.Trie树是多叉树,每个节点为一个字母.其根节点为象征节点(就是说没有含义,但是存在这个节点),从根节点开

【暖*墟】 #AC自动机# 多模式串的匹配运用

一.构建步骤 1.将所有模式串构建成 Trie 树 2.对 Trie 上所有节点构建前缀指针(类似kmp中的next数组) 3.利用前缀指针对主串进行匹配 AC自动机关键点一:trie字典树的构建过程 字典树的构建过程是这样的,当要插入许多单词的时候,我们要从前往后遍历整个字符串, 当我们发现当前要插入的字符其节点再先前已经建成,我们直接去考虑下一个字符即可, 当我们发现当前要插入的字符没有再其前一个字符所形成的树下没有自己的节点, 我们就要创建一个新节点来表示这个字符,接下往下遍历其他的字符.

图解AC自动机

图解AC自动机 前言: 我们引出这样一个问题: 我想知道字符串\(t\)在字符串中\(s\)出现多少次/有没有出现? 那我们可以使用kmp算法求出\(t\)的next数组,之后\(O(n)\)匹配求解即可. 那如果把问题升级一下呢? 想知道字符串\(t_1,t_2,...,t_n\)在字符串\(s\)中出现了多少次/有没有出现? 这时候再用\(kmp\)算法,复杂度将达到\(O(n^2)\),非常慢了. 这时候我们需要AC自动机. AC自动机用于求解多个模式串与一个文本串的匹配问题. AC自动机