一发kuangbin~~AC自动机版子,带注解,计数的作用。

屌丝的字典树。。。醉了。。。#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <cstdlib>

using namespace std;

struct Trie
{
    int next[500010][26],fail[500010],isend[500010];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 26;i++)//这个串的跳转清空
            next[L][i] = -1;
        isend[L++] = 0;//不是节点层
        return L-1;//返回这个点的序号
    }
    void init()
    {
        L = 0;
        root = newnode();//给根一个点
    }
    void Insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][buf[i]-‘a‘] == -1)//当前字典层中没有这个字符
                next[now][buf[i]-‘a‘] = newnode();//指向生成新的点,并且这点有字符
            now = next[now][buf[i]-‘a‘];//去新的点位继续操作
        }
        isend[now]++;//这层是结点层,标记
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;//根节点仍然是根节点
        for(int i = 0;i < 26;i++)//对第一个字符遍历
            if(next[root][i] == -1)//没有此字符开头
                next[root][i] = root;//跳转到根
            else//有此字符开头的
            {
                fail[next[root][i]] = root;//这个行位的失败指针为根
                Q.push(next[root][i]);//行放入队列
            }
        while( !Q.empty() )//还有字符
        {
            int now = Q.front();//逐层拿出第一个
            Q.pop();
            for(int i = 0;i < 26;i++)//对这一行
                if(next[now][i] == -1)//如果下一行没有这个字符
                    next[now][i] = next[fail[now]][i];//他的下一个的这个位置,是回到这个点父节点的下一个(回头)
                else//如果有这个字符
                {
                    fail[next[now][i]]=next[fail[now]][i];//他的下一个的这个位置的失败指针,是这个点父节点的下一个
                    Q.push(next[now][i]);//下一行继续
                }
        }
    }
    int query(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        int res = 0;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]-‘a‘];
            int temp = now;
            while( temp != root )
            {
                res += isend[temp];
                isend[temp] = 0;
                temp = fail[temp];
            }
        }
        return res;
    }
    void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],isend[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
};
char buf[1000010];
Trie ac;
int main()
{
    int T;
    int n;
    scanf("%d",&T);
    while( T-- )
    {
        scanf("%d",&n);
        ac.init();
        for(int i = 0;i < n;i++)
        {
            scanf("%s",buf);
            ac.Insert(buf);
        }
        ac.build();
        scanf("%s",buf);
        printf("%d\n",ac.query(buf));
    }
    return 0;
}
时间: 2024-10-30 03:24:17

一发kuangbin~~AC自动机版子,带注解,计数的作用。的相关文章

AC自动机(AC automation)

字典树+KMP 参考自: http://www.cppblog.com/mythit/archive/2009/04/21/80633.html 1 const int MAXN = 26; //字典大小 2 3 //定义结点 4 struct node{ 5 node* fail; 6 node* child[MAXN]; 7 int count; 8 node(){ 9 fail = NULL; 10 count = 0; 11 memset(child, NULL, sizeof(chil

LA 4670 (AC自动机 模板题) Dominating Patterns

AC自动机大名叫Aho-Corasick Automata,不知道的还以为是能自动AC的呢,虽然它确实能帮你AC一些题目.=_=|| AC自动机看了好几天了,作用就是多个模式串在文本串上的匹配. 因为有多个模式串构成了一颗Tire树,不能像以前一样线性递推失配函数f了,于是改成了BFS求失配函数. 白书上那个last数组(后缀链接)的含义就是:在Tire树的某个分支上虽然没有遇到单词节点,但是某个单词可能是已经匹配上的字串的后缀. 举个栗子: 有两个模式串:aaabbb, ab 现在已经匹配了a

高效处理字符串!——AC自动机

AC自动机 这两天进军AC自动机算法,越做越觉得这种算法的灵活与高效,接下来对这阵子的学习做个总结. AC自动机,当然它最主要的作用是自动帮你AC题目多模式串的匹配,也就是字典树trie和kmp的结合,再深入讲就是把kmp中失配时跳转的思想运用到trie上! 1.AC自动机构建 对于构建,基本上都是模板,先建trie,再BFS这颗trie从而构建出最重要的fail指针,即失配跳转指针(口头表达),fail指针指向的是当前状态的最长后继.         而一般我们为了加快速度,每个节点还会构建类

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

模板]AC自动机(简单版) https://www.luogu.org/problemnew/show/P3808 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意 题目描述 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. 输入输出格式 输入格式: 第一行一个n,表示模式串个数: 下面n行每行一个模式串: 下面一行一个文本串. 输

Uva 11468 改良版AC自动机

改良版AC自动机 UVa 11468 题意:给一些字符和各自出现的概率,在其中随机选择L次,形成长度为L的字符串S,给定K个模板串,求S不包含任意一个串的概率. 首先介绍改良版的AC自动机: 传统的AC自动机,是当一个字符失配时,根据失配函数转移到指定地方,而这个失配函数,是通过一个宽搜的过程形成的,这时在匹配串的时候,就当匹配失败时,顺着失配指针走,直到可以匹配.然后匹配到单词结点,或者后缀链接是一个单词结点,这些前面的结点也是匹配单词.这就是传统的AC自动机. 现在将这个AC自动机改版优化:

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

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &

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

题目背景 通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名. 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意 题目描述 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. 输入格式 第一行一个n,表示模式串个数: 下面n行每行一个模式串: 下面一行一个文本串. 输出格式 一个数表示答案 输入输出样例 输入 #1复制 2 a

转自kuangbin的AC自动机(赛前最后一博)

有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配.           AC自动机 其实 就是创建了一个状态的转移图,思想很重要.           推荐的学习链接: http://acm.uestc.edu.cn/bbs/read.php?tid=4294 http://blog.csdn.net/niushuai666/article/details/7002823 http://hi.baidu.com/nial

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

题目背景 这是一道简单的AC自动机模版题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 题目描述 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. 输入输出格式 输入格式: 第一行一个n,表示模式串个数: 下面n行每行一个模式串: 下面一行一个文本串. 输出格式: 一个数表示答案 输入输出样例 输入样例#1: 2 a aa aa 输出样例#1: 2 说明 subtask1[50pts]:∑length(模式串)<=10^6,len