自动机

C# 词法分析器(三)正则表达式

你离开我真会死。 提交于 2020-01-05 00:46:10
系列导航 (一)词法分析介绍 (二)输入缓冲和代码定位 (三)正则表达式 (四)构造 NFA (五)转换 DFA (六)构造词法分析器 (七)总结 正则表达式是一种描述词素的重要表示方法。虽然正则表达式并不能表达出所有可能的模式(例如“由等数量的 a 和 b 组成的字符串”),但是它可以非常高效的描述处理词法单元时要用到的模式类型。 一、正则表达式的定义 正则表达式可以由较小的正则表达式按照规则递归地构建。每个正则表达式 $r$ 表示一个语言 $L(r)$,而语言可以认为是一个字符串的集合。正则表达式有以下两个基本要素: $\epsilon$ 是一个正则表达式, $L( \epsilon ) = { \epsilon }$,即该语言只包含空串(长度为 0 的字符串)。 如果 $a$ 是一个字符,那么 $\bf{ a }$ 是一个正则表达式,并且 $L( \bf{a} ) = \{ a \}$,即该语言只包含一个长度为 $1$ 的字符串 $a$。 由小的正则表达式构造较大的正则表达式的步骤有以下四个部分。假定 $r$ 和 $s$ 都是正则表达式,分别表示语言 $L(r)$ 和 $L(s)$,那么: $(r)|(s)$ 是一个正则表达式,表示语言 $L(r) \cup L(s)$,即属于 $L(r)$ 的字符串和属于 $L(s)$ 的字符串的集合( $L(r) \cup L(s) =

字符串匹配算法——利用有限自动机进行匹配

前提是你 提交于 2019-12-22 15:29:31
  本文内容与《算法导论》中字符串匹配章节相关并部分摘录。   常用的字符串匹配算法有朴素字符串匹配算法,Rabin-Karp算法,利用有限自动机进行字符串匹配和KMP算法等。前面两种比较简单,重点是后面两种。 利用有限自动机进行字符串匹配   假设要对文本字符串T进行扫描,找出模式P的所有出现位置。这个方法可以通过一些办法先对模式P进行预处理,然后只需要对T的每个文本字符检查一次,并且检查每个文本字符所用时间为常数,所以在预处理建好自动机之后进行匹配所需时间只是Θ(n)。   假设文本长度为n,模式长度为m,则自动机将会有0,1,...,m这么多种状态,并且初始状态为0。先抛开自动机是怎样计算出来的细节,只关注自动机的作用。在从文本从左到右扫描时,对于每一个字符a,根据自动机当前的状态还有a的值可以找出自动机的下一个状态,这样一直扫描下去,并且一定自动机状态值变为m的时候我们就可以认为成功进行了一次匹配。先看下面简单的例子: 假设现在文本和模式只有三种字符a,b,c,已经文本T为"abababaca",模式P为"ababaca",根据模式P建立自动机如下图(b)(先不管实现细节):   (a)图为一些状态转化细节 如图(c),对照自动机转换图(b),一个个的扫描文本字符,扫描前状态值初始化为0,这样在i = 9的时候状态值刚好变成7 = m,所以完成一个匹配。  

AC自动机fail树上dfs序建线段树+动态memset清空

蓝咒 提交于 2019-12-20 04:21:27
题意: http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路: https://blog.csdn.net/u013306830/article/details/77586562 主要就是卡你内存,AC自动机的字典树得要用了再清空。 代码有点长吧。。。 1 #include <cstdio>//sprintf islower isupper 2 #include <iostream>//pair 3 #include <string.h>//strstr substr strcat 4 #include <queue>//priority_queue<int, vector<int>, greater<int> > q;//less 5 using namespace std;//next_permutation(a+1,a+1+n);//prev_permutation 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 #define pr printf 8 #define sc scanf 9 #define ls rt<<1 10 #define rs rt<<1|1 11 const int N=3e5+10; 12 13 char s[N]; 14 int pos[20004],val

AC自动机入门

别等时光非礼了梦想. 提交于 2019-12-17 19:12:12
AC自动机入门 我学的时候看的是 yyb的博客 链接一个 神奇的东西 讲之前的bb PS :不要想着马上能理解AC自动机, 那是不可能的 。 建议先大致理解一下,然后敲几次板子,这样虽然自己心里不爽,但是在敲板子的过程中就会慢慢理解了 一.算法基础 1.KMP字符串匹配 2.trie树 要求入门并能有一定技巧地运用 二.由来 (匹配泛指各种字符串之间相互包含,交集等问题) 我们学习了KMP,是用来 2 个字符串匹配的算法:O(m+n) 现在给出很多个字符串,去把他们和另外一个字符串匹配,如果逐个匹配,显然会很慢,所以引入一种新算法:AC自动机 这个是分割线吧? 正式开始: 主要思想 Q:多个字符串? A:我们学了trie树是吧,预备一下,把要被匹配的字符串全丢进去 Q:字符串匹配? A:我们学了KMP对吧,想一下KMP的原理,突然发现next[]是不是很吊,预处理出来。 肯定有用,但是肯定预处理方法不同(见后) Q:这个我也想得到啊! A:所以肯定是一个KMP结合trie树的算法,它就叫AC自动机 实现 注意 :以 luogu AC自动机模板 为例 首先一个图,自己画下来再根据代码模拟手玩更容易理解 来自yyb: Insert 一 . 先把所有的匹配字符串丢进trie树,这个不用多说 ljl[].son[] 表示now的每一个儿子(26个字母) 板子 ljl[].end

【NOI2015】品酒大会

空扰寡人 提交于 2019-12-11 14:30:26
后缀自动机 首先考虑第一问: 我们先将后缀自动机建出来,考虑每个节点,它出现的次数肯定是endpos的size(我们记为num),那么选取这个节点的串的方案数即为C(num,2)=num*(num-1)/2,所能贡献的长度区间为这个节点对应的所有串的长度即[ len[fa[x]]+1 , len[x]+1 ],这里可以差分一下,最后前缀和就是答案了。 然后考虑第二问: 我们考虑每当我们在后缀自动机上新建一个节点,就把这个位置的a[i]给赋值上去。当然,在建的过程中由于endpos裂开而产生的的那个新的节点不赋值,因为最后因endpos裂开的而产生的新节点的nq在parent tree上一定是原节点q的father,所以最后的值会更新上去,如果赋值了,就相当于额外多了一个值,答案当然会不对。 那么我们再考虑在parent tree上应该怎么做。在parent tree上,father一定是son的后缀,而对于这题来说,某两个串是r相似的,那么它们一定是[0,r-1]相似的,即一对r相似串的a1*a2有贡献那么对它们的前缀一定也有贡献,所以我们可以将串倒序建后缀自动机,这样后缀就变成了前缀,lcp就变成了lca!因为此题a有负数,所以我们要维护最大次大最小次小,那么因为现在parent tree上每个父亲都是儿子的前缀,所以子树的最优可以更新父亲的最优

【HAOI2016】找相同字符

拜拜、爱过 提交于 2019-12-11 12:24:56
后缀自动机入门题 分别对两个串建后缀自动机,然后把endpos的大小算出来,最后在两个后缀自动机上一起dfs一遍并且算答案。 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int maxn=5e5+10; int n; char s[maxn]; long long ans; struct suda { struct da{int ch[30],fa,len;}po[maxn]; int las,tot,si[maxn],to[maxn],nt[maxn],st[maxn],topt; void init() { memset(po,0,sizeof po); memset(si,0,sizeof si); memset(to,0,sizeof to); memset(nt,0,sizeof nt); memset(st,0,sizeof st); las=tot=1; topt=0; } void insert(int x) { int p=las,np=las=++tot; po[np].len=po[p].len+1; si[np]=1; for (;p&&(!po[p].ch[x]);p=po[p].fa) po[p

回文自动机[学习笔记]

佐手、 提交于 2019-12-09 11:17:04
回文自动机一一处理回文串问题的有力武器 这几天一直沉迷字符串数据结构 看了很多大佬的回文自动机学习笔记,稍微有点理解了,整理一下吧 1.概念 \(\quad\) a.大概: 同其他自动机一样,回文自动机是个DAG,它用相当少( \(O(n)\) )的空间复杂度就存储了这个字符串的所有回文串信息。一个回文自动机包含不超过 \(|S|\) 个节点,每个节点都表示了这个字符串的一个不重复的回文子串,同时一个节点会有不超过字符集大小的边连向其他节点,以及一条fail边连向这个点的fail...这些都会在下面介绍 \(\quad\) b.森林: 和别的自动机不太一样,回文自动机是有两棵树的森林:其中一棵是长度为偶数的回文串集合,另一棵是长度为奇数的回文串集合,这两棵树的根节点分别表示长度为0(空串)和-1(无实际含义,便于运算)的回文串; \(\quad\) c.边:自动机中每条有向边都有一个字符类型的权值,起点的串左右分别加上这个字符得到的就是终点的串。举个栗子:设一条边权为 \(c\) 的边连接的两个点分别是 \(A,B\) , \(A\) 表示回文串 \(aba\) ,则 \(B\) 表示的回文串就是 \(cabac\) 。特别的,如果 \(A\) 是那个长度为 \(-1\) 的根, \(B\) 串就是这条边的权值。。。 \(\quad\) d.点:当你插入一个字符的时候

后缀自动机感性理解

心不动则不痛 提交于 2019-12-08 09:39:24
后缀自动机感性理解 后缀自动机实是不是很好理解, 尤其是直接看大段的证明, 不知道它在干什么, 可能会有点懵 那我先介绍一下我的感性理解好了, 大家看这篇文章可能会更好的理解其他人的博客QAQ 前置芝士 : trie树 先来讲一下假后缀树($ n^2 $) , 由于它是假的所以很容易理解, 不用怕 偷图.jpg 对于一个字符串(例: \(bananas\) )来说, 把它的所有后缀($bananas, ananas, nanas, anas, nas, as, s \() 一个一个的插入trie树, 并在末尾打上end标记, 就是暴力的后缀\) trie \(了, 显然时空复杂度均为\) O(n^2)$ 那么可以说后缀自动机是对它很大程度上的优化了, 也就是对重复出现的子串和后缀进行压缩等操作, 使时空复杂度骤降为 \(O(n)\) , 并具有后缀树的一些性质 关于子串的理解: 对于字符串S的一个子串, 你可以理解它为((S的一个后缀)的前缀), 没毛病 也就是如果S的一个子串在trie上一定是一条从根节点开始的路径 有啥用呢 找一个子串的出现次数: 在trie上找到它的路径, 在它下方的end标记之和, 也就是它是多少个后缀的前缀 找一个子串第一次(最后一次)出现位置, 同上, 就是向下走到深度最大(深度最小)的end标记 统计本质不同子串的个数, 即trie树上节点的个数

前置内容1:算法与数据结构

我是研究僧i 提交于 2019-12-06 08:42:38
信息学竞赛的主要考点就是算法与数据结构。 算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。 简单来说,算法用于解决一个具体的问题,应该具有几个性质:确切性,有限性,输入输出,可行性。 也就是说,一个算法应该首先是确定的,而不是模棱两可的;其次是可以在有限的时间和步数内完成;另外需要有输入和输出(输入可以没有,但输出必然需要);所有的基本操作都是可以完成的。 属于OI范围的算法主要包括: 基本算法:包括枚举,模拟,贪心,二分,排序等。它们是其他算法或数据结构的基础; 搜索算法:包括深度优先搜索(DFS),广度优先搜索(BFS)及其优化。搜索是比较接近暴力的算法,但是又有很多优化型内容,例如迭代加深搜索(ID-DFS),A*算法等,在NOIP普及组和提高组中非常重要; 动态规划(DP):包括线性动态规划,多维动态规划,树形动态规划,状态压缩动态规划,图论动态规划等,还有一些拓展的类型,如期望DP,插头DP,数位DP,动态DP等。动态规划是较难的算法,无论是什么等级的比赛中动态规划都是极其重要的; 图论算法:包括最短路算法(SP),最小生成树(MST),拓扑排序,无向图的割边和割点,有向图的强连通分量(SCC),二分图匹配

AC自动机fail树上dfs序建线段树+动态memset清空

纵饮孤独 提交于 2019-12-06 03:31:08
题意: http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路: https://blog.csdn.net/u013306830/article/details/77586562 主要就是卡你内存,AC自动机的字典树得要用了再清空。 代码有点长吧。。。 1 #include <cstdio>//sprintf islower isupper 2 #include <iostream>//pair 3 #include <string.h>//strstr substr strcat 4 #include <queue>//priority_queue<int, vector<int>, greater<int> > q;//less 5 using namespace std;//next_permutation(a+1,a+1+n);//prev_permutation 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 #define pr printf 8 #define sc scanf 9 #define ls rt<<1 10 #define rs rt<<1|1 11 const int N=3e5+10; 12 13 char s[N]; 14 int pos[20004],val