自动机

BZOJ 2565 最长双回文串

烂漫一生 提交于 2020-04-07 05:49:03
题目链接: 最长双回文串   回文自动机第三题。   正反各构一个回文自动机,就可以得到以每个位置开头和结尾的最长回文串了。   然后枚举一下断点就做完了。   下面贴代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 500010 using namespace std; typedef long long llg; char a[maxn]; int ans; struct PAM{ int l[maxn],s[maxn][26],f[maxn]; int tt,la,ans,dt,g[maxn]; PAM(){f[0]=1,l[++tt]=-1;} void add(int c,int n){ int p=la; while(a[n-l[p]-1]!=a[n]) p=f[p]; if(!s[p][c]){ int np=++tt,k=f[p]; l[np]=l[p]+2; while(a[n-l[k]-1]!=a[n]) k=f[k]; f[np]=s[k][c]; s[p][c

如何将 不确定的有穷自动机(NFA) 转化为 确定的有穷自动机(DFA) 并将DFA最简化

与世无争的帅哥 提交于 2020-03-29 20:26:09
一、从NFA到DFA的转换 例如下图: DFA的每个状态都是一个由NFA中的状态构成的集合,即NFA状态集合的一个子集 r =aa*bb*cc* 二、从带有ε-边的NFA到DFA的转换 r=0*1*2* 三、子集构造法( subset construction)  输入:NFA N  输出:接收同样语言的DFA D  方法:一开始,ε-closure ( s0 )是Dstates 中的唯一状态,且它未加标记; while(在Dstates中有一个未标记状态T ) { 给T加上标记; for(每个输入符号a) { U = ε-closure(move(T, a)); if ( U不在Dstates中) 将U加入到Dstates中,且不加标记; Dtran[T, a]=U ; } } 四、计算 ε-closure (T ) 将T的所有状态压入stack中;将ε-closure (T )初始化为 T ; while(stack非空) {   将栈顶元素 t 给弹出栈中;   for(每个满足如下条件的u :从t出发有一个标号为ε的转换到达状态u)     if ( u不在ε-closure (T )中)     {       将u加入到ε-closure (T )中;将u压入栈中;     } } 接下来我们结合一个例题来具体实践一下根据正规文法构造NFA,接着确定化NFA

编译原理DFA(有限确定自动机)的构造

ε祈祈猫儿з 提交于 2020-03-18 06:49:57
CODE: https://github.com/pxjw/Principles-of-Compiler/tree/master/consDFA 原题: 1、自己定义一个简单语言或者一个右线性正规文法 示例如( 仅供参考 ) G[S]:S→aU|bV U→bV|aQ V→aU|bQ Q→aQ|bQ|e 2、构造其有穷确定自动机,如 3、利用有穷确定自动机M=(K,Σ,f, S,Z)行为模拟程序算法,来对于任意给定的串,若属于该语言时,该过程经有限次计算后就会停止并回答“是”,若不属于,要么能停止并回答“不是” K:=S; c:=getchar; while c<>eof do {K:=f(K,c); c:=getchar; }; if K is in Z then return (‘yes’) else return (‘no’) 开始编程! 1.状态转换式构造类: current——当前状态 next——下一状态 class TransTile { public: char current; char next; char input; TransTile(char C,char I,char Ne){ current = C; next = Ne; input = I; } }; 2.DFA的构造类 此处包括DFA的数据集,字母表,以及过程P的定义。 包括了初始化,遍历转换

AC自动机

点点圈 提交于 2020-03-18 05:09:44
去年就见到过这个词,不过一直没有去看,不是很理解其中的算法,可能是对kmp还没能够了解透彻。。 一个常见的例子就是给出 n 个单词,再给出一段包含 m 个字符的文章,让你找出有多少个单词在文章里出现过。 要搞懂 AC 自动机,先得有模式树(字典树) Trie 和 KMP 模式匹配算法的基础知识。 AC 自动机算法分为 3 步:构造一棵 Trie 树,构造失败指针和模式匹配过程。 详见: http://www.cppblog.com/mythit/archive/2009/04/21/80633.html (AC自动机算法详解) 贴个模板吧: hdu 2222 经典ac自动机 # include<stdio.h> # include<queue> # include<string.h> # define MAX 26 using namespace std; struct Trie{ int count; struct Trie *next[MAX],*fail; }; queue<Trie *>q; char keyword[55];//记录单词 char str[1000005];//记录模式串 Trie *NewTrie() { int i; Trie *temp=new Trie; temp->count=0; for(i=0;i<MAX;i++) temp->next[i]

AC自动机算法详解(入门)

空扰寡人 提交于 2020-03-14 04:20:13
AC自动机算法详解 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。 如果你对KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干什么用的。KMP中我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符,当A[i+1]≠B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配,而next函数恰恰记录了这个j应该调整到的位置。同样AC自动机的失败指针具有同样的功能,也就是说当我们的模式串在Tire上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。 看下面这个例子:给定5个单词:say she shr he her

AC 自动机 [学习笔记]

独自空忆成欢 提交于 2020-03-10 19:34:13
突然想起来还有这么一个东西我没有写过学习笔记的 AC 自动机的三个板子 P5357 【模板】AC自动机(二次加强版) P3808 【模板】AC自动机(简单版) P3796 【模板】AC自动机(加强版) 首先你需要会字典树,最好会 kmp ,不会也无所谓。 AC 自动机我个人觉得和 \(kmp\) 没啥联系,只和字典树有关系2333,因为 AC 自动机是 基于字典树上的bfs 建造出来的。 如果给你几个串,你 \(kmp\) 的复杂度显然不可以接受,所以就需要我们的 AC 自动机了。 我个人习惯从 \(cnt = 1\) 开始,即字典树的 \(root\) 为 \(1\) ,以及 \(ch_{u,i}\) 来表示字典树的节点, 我更倾向于把字典树的一个节点当做是字符串,因为从根节点顺次下来确实是一个字符串。 首先你要明白 \(fail_i\) 和 \(i\) 的关系是 \(fail_i\) 是 \(i\) 的子串,以及,当你构造完 AC 自动机之后, \(ch_{u,i}\) 不一定是原字典树的样子 ,就是说会相对于字典树的结构变化,比如说跨越层,但是并不难理解,其实就是为了 \(fail\) 的转移。 如果实际需要,比如说 这一题 ,你就可以先复制原有节点,然后建 AC 自动机。 \(fail_i -> i\) 连边会成为一棵树,而树内查询之类的可以用树状数组等数据结构维护

Poj1625 AC自动机+大数+DP

醉酒当歌 提交于 2020-03-07 03:09:39
poj1625 题意 给一个含n个字符的字符集,p个字符串,问长度为m的字符串有多少种不包含任意一个字符串pi。 题解 首先这题应该想到dp,dp[i][j]表示长度为i的字符串以节点j(节点j表示一个AC自动机上的一个状态节点)结尾的满足条件的字符串种类。以p个字符串建立AC自动机,标记危险节点。想像一个这样的问题:假设当前在u节点,u节点就表示当前长度为x的字符串,从u经过状态转移到其他节点,那么字符串的长度就变为x+1,遍历每个节点,如果该节点不是危险节点,则dp[i][j] = dp[i][j] + dp[i - 1][u],(j是u的一个子节点),这样从根结点(空串)转移m次到达的合法节点就是所求解。 注意:①数据很大,要用到大数模板 ②字符有坑,会大于127,要用unsigned char 读入 ③这里的AC自动机的模板还要改动一下,因为每个合法节点要进行状态转移,有些节点每个某个子节点,这样无法转移,所以将其的子节点指向它fail节点的对应的子节点(具体看代码注释)。 # include <iostream> # include <cstdio> # include <string.h> # include <map> # include <queue> using namespace std ; typedef unsigned char uchar ;

[BZOJ5417] [NOI2018]你的名字

情到浓时终转凉″ 提交于 2020-03-02 07:55:40
Description 小A 被选为了ION2018 的出题人,他精心准备了一道质量十分高的题目,且已经把除了题目命名以外的工作都做好了。 由于ION 已经举办了很多届,所以在题目命名上也是有规定的,ION 命题手册规定:每年由命题委员会规定一个小写字母字符串,我们称之为那一年的命名串,要求每道题的名字必须是那一年的命名串的一个非空连续子串,且不能和前一年的任何一道题目的名字相同。 由于一些特殊的原因,小A 不知道ION2017 每道题的名字,但是他通过一些特殊手段得到了ION2017 的命名串,现在小A 有Q 次询问:每次给定ION2017 的命名串和ION2018 的命名串,求有几种题目的命名,使得这个名字一定满足命题委员会的规定,即是ION2018 的命名串的一个非空连续子串且一定不会和ION2017 的任何一道题目的名字相同。 由于一些特殊原因,所有询问给出的ION2017 的命名串都是某个串的连续子串,详细可见输入格式。 Input 第一行一个字符串S ,之后询问给出的ION2017 的命名串都是S 的连续子串。 第二行一个正整数Q,表示询问次数。 接下来Q 行,每行有一个字符串T 和两个正整数l,r,表示询问如果ION2017 的 命名串是S [l..r],ION2018 的命名串是T 的话,有几种命名方式一定满足规定。 Output 输出Q 行,第i

AC自动机

感情迁移 提交于 2020-02-27 05:10:59
首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。KMP算法是单模式串的字符匹配算法,AC自动机是多模式串的字符匹配算法。 AC自动机和字典树的关系比较大,所以先来简单的了解下字典树Trie。 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。 简而言之:字典树就是像平时使用的字典一样的,我们把所有的单词编排入一个字典里面,当我们查找单词的时候,我们首先看单词首字母,进入首字母所再的树枝,然后看第二个字母,再进入相应的树枝,假如该单词再字典树中存在,那么我们只用花费单词长度的时间查询到这个单词。 AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。 AC自动机关键点一:字典树的构建过程: 字典树的构建过程是这样的,当要插入许多单词的时候,我们要从前往后遍历整个字符串

BZOJ 3676: [Apio2014]回文串

百般思念 提交于 2020-02-25 01:20:21
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2013 Solved: 863 [ Submit ][ Status ][ Discuss ] Description 考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最 大出现值。 Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。 Output 输出一个整数,为逝查回文子串的最大出现值。 Sample Input 【样例输入l】 abacaba 【样例输入2] www Sample Output 【样例输出l】 7 【样例输出2] 4 HINT 一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。 在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中: ● a出现4次,其出现值为4:1:1=4 ● b出现2次,其出现值为2:1:1=2 ● c出现1次,其出现值为l:1:l=l ● aba出现2次,其出现值为2:1:3=6 ● aca出现1次,其出现值为1=1:3=3 ●bacab出现1次,其出现值为1:1:5=5 ● abacaba出现1次,其出现值为1:1:7=7