AC自动机总结

AC自动机总结

自动机的概念:

自动机又称有限状态机,是从初始状态不断接受输入,根据输入数据和当前状态跳转到下一状态的一种机器。

AC自动机可以实现多串匹配单串。复杂度是\(O(n+m)\),也就是匹配串长+模式串总长。
AC自动机匹配失配时,类似KMP算法的next数组,AC自动机上有fail指针可以跳到下一个应该进行匹配的状态。
fail指针的一般定义是:沿着父亲的fail指针一直向上跳,直到跳到某一个节点,这个节点拥有与自己相同字母的子节点,那么fail指针就指向这个相同字母的子节点。
一般写起来是这样的

void Get_Fail()
{
    for (int i=0;i<26;i++) if (ch[i][0]) Q.push(ch[i][0]);
    while (!Q.empty())
    {
        int u=Q.front();Q.pop();
        for (int i=0;i<26;i++)
            if (ch[i][u]) fail[ch[i][u]]=ch[i][fail[u]],Q.push(ch[i][u]);
            else ch[i][u]=ch[i][fail[u]];
    }
}

这样相当于建出了一个Trie图,使得每个节点都拥有了26个儿子。如果你想要保存原Trie树的话请先备份。
一般来说插入一个模式串就是

void Insert(string c,int ID)
{
    int l=c.length(),x=0;
    for (int i=0;i<l;i++)
    {
        if (!ch[c[i]-'a'][x]) ch[c[i]-'a'][x]=++tot;
        x=ch[c[i]-'a'][x];
    }
    id[x]=ID;
}

然后因为AC自动机本身就和“状态”关系密切,所以AC自动机上往往会用来跑DP。
然后如果你不记得KMP怎么写了也可以写AC自动机。

几个小tips

如果是给出若干个串求匹配,由fail指针串起来的点是一个点,意思是如果你匹配了一个串,那么你同时也匹配了这个串的任意后缀。所以你在AC自动机上每走过一个点,就要暴跳fail到root进行匹配。
但如果是给出若干不合法串求合法方案数,这时由fail指针串起来的点就不是一个点,因为假使认为是同一个点会导致不合法状态计入。同时,不合法标记要沿着fail下传,意思是如果某一个串不合法,那么以这个串为前缀的任意串都不合法。

题目也不算多,因为基本上都是一样的,所以就不放代码直接嘴巴AC了。

[HNOI2004]L语言

题面
设\(f_i\)表示文章的前\(i\)个字符是否可以被理解。每次匹配要暴跳fail到根,转移就是\(f_i|=f_{i-len}\),其中\(len\)是某个可以匹配的模式串的串长。
code

[USACO15FEB]审查Censoring

题面
开一个栈记录依次经过的AC自动机上的节点编号以及这一次的字母,若匹配到一个串就直接弹掉栈顶的\(len\)个元素,\(len\)为匹配到的模式串长度。弹栈顶直接\(top-=len\)即可。
code

[SDOI2014]数数

题面
AC自动机做数位DP。首先位数小于\(n\)的位数的数只要满足没有不合法串即可,记\(f_{i,j}\)表示填了\(i\)个数,当前在AC自动机上编号为\(j\)的节点上的方案数,取答案\(\sum_{i=1}^{n-1}\sum_{j=0}^{tot}f_{i,j}\)。
位数等于\(n\)的,在前面那个状态上多加一维,表示是否已经严格小于那个数,然后按照数位DP的一般思路卡一卡就好了。
code

[HNOI2008]GT (搞颓)考试

题面
先考虑\(O(nm)\)的转移。设\(f_{i,j}\)表示填了\(i\)个数,当前在AC自动机上编号为\(j\)的节点上的方案数(和上面的一模一样)。
发现每次从\(f_i\)转移到\(f_{i+1}\)的转移都是一样的,所以可以矩阵快速幂优化DP转移,复杂度\(O(m^3\log{n})\)
code
(留坑待补。。。)

原文地址:https://www.cnblogs.com/zhoushuyu/p/8343863.html

时间: 2024-11-08 07:47:58

AC自动机总结的相关文章

暑假集训day9补充(AC自动机)

推荐网站http://blog.csdn.net/niushuai666/article/details/7002823 AC自动机嘛,此AC(aho-corasick)非彼AC(Accepted). 我也不是很会解释 有一题是必须打的hdu2222. #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int mn=

ac自动机基础模板(hdu2222)

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users type some keywords to find the image, th

HDU 2825 Wireless Password AC自动机+dp

训练赛第二场的I题,上完体育课回来就把这题过了,今天训练赛rank1了,还把大大队虐了,而且我还过了这道题 (虽然我也就过了这道题...),第一次在比赛中手写AC自动机还带dp的,心情大好. 给一个字符串集合,求包含该集合超过K个字符的,长度为L的字符串的个数. 显然是在AC自动机上跑dp,设dp[u][L][k]表示当前在结点u,还要走L步,当前状态为k的个数.一开始第三维表示的是包含k个字符串,但是题目要求不含重复的,那就只能状压了.转移为dp[u][L][k]+=dp[v][L-1][nk

HDU 2896-病毒侵袭(ac自动机)

题意: 给定多个模式串,每给一个母串,输出包含模式串的编号,最后输出包含模式串的母串的数量. 分析: ac自动机模板 #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vector> #include <st

hdu2222 Keywords Search &amp; AC自动机学习小结

传送门:http://http://acm.hdu.edu.cn/showproblem.php?pid=2222 思路:AC自动机入门题,直接上AC自动机即可. 对于构建AC自动机,我们要做的只有三件事: 1)构建字典树 2)构建失败指针 3)构建trie图(这道题好像不做这一步也能A...但是这一步不做是会被卡成O(n^2)的...) 1)第一步还是比较好理解的 根是虚根,边代表字母,那么根到终止节点的路径就是一个字符串,这样对于前缀相同的字符串我们就可以省下存公共前缀的空间. 加入一个模式

hdoj 2896 病毒侵袭(AC自动机)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896 思路分析:题目为模式匹配问题,对于一个给定的字符串,判断能匹配多少个模式:该问题需要静态建树,另外需要对AC自动机的模板加以修改, 对于每个匹配的模式的最后一个单词的fail指针指向root,即可实现一个字符串进行多次模式匹配: 代码如下: #include <queue> #include <cstdio> #include <cstring> #include &

从Trie谈到AC自动机

ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字母,因此得名`字母树`. 出一张图让大家感受下. (image powered by SaiBu NaoCu) 上面那是一棵插入了 ape,app,applicant,application,bake,ban,banana 等词的Trie.红色结点表示接受态. 显然,查找时只需顺着链照下来,插入只需

AC自动机

AC自动机 直接学AC自动机比较难理解,强烈建议先学完KMP和字典树并进行一定的练习后,对于失配指针和字典树构造有一定理解后再来学AC自动机的内容.有关AC自动机的详细介绍可见刘汝佳的<算法竞赛入门经典训练指南>P214. 给你一个字典(包含n个不重复的单词),然后给你一串连续的字符串文本(长为len),问你该文本里面的哪些位置正好出现了字典中的某一个或某几个单词?输出这些位置以及出现的单词. 这个问题可以用n个单词的n次KMP算法来做(效率为O(n*len*单词平均长度)),也可以用1个字典

【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)

题意: 多组数据,每组求第n个包含'666'的数(不能断开),如1:666,2:1666,14:6667. 题解: AC自动机解法没去想,数位DP没学,这里有一种类似于数位DP,却又与数位DP不同,我称为数位树. 数位树: 将数n如线段树一样地拆分成多个小段,进行递归处理得出答案. 本题详(lue)解: 直接看每一位应该是什么数,然后n减去相应的数,使得在下一层转换为子问题"在开头有b个连续的6时,求第a个带'666'的数".就是如此简单,如此简单!!!! 代码来啦! #include

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

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