P3808 【模板】AC自动机(简单版)
题目背景
这是一道简单的AC自动机模板题。
用于检测正确性以及算法常数。
为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。
管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意
题目描述
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入输出格式
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案
输入输出样例
2
a
aa
aa
2
说明
subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;
subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;
Solution:
AC自动机板子。
简单讲一下,对于多模式串的匹配,如果都用kmp解决则主串要扫多次,复杂度直接变为$O(n^2)$。
而AC自动机可以只扫一次主串进行多模式串匹配,先将所有模式串构建出一棵trie树,然后类比kmp我们在trie树上构建失配边,每次失配直接跳向失配边所指指针继续匹配,这样就能将匹配的时间复杂度变为$O(\sum{|P|}+|T|)$,至于求失配边我们可以类比kmp的next数组求法,将递归改为在trie树上bfs递推,递推很好理解直接见代码。
解释一下fail数组:根节点到$fail[i]$表示的字符串,是根节点到$i$表示的字符串的最长后缀。
这样就能保证到了$i$节点时,根节点到$fail[i]$所表示的字符串一定出现过,失配时就能接上去继续匹配。
小技巧:
1、在AC自动机的构建时,往往会有一个类似路径压缩的优化:当不存在$trie[p][i]$节点时,直接$trie[p][i]=trie[fail[p]][i]$,即将该空节点指向其失配边所指节点的该字符节点。
2、匹配时往往会多次走失配边,影响效率,于是另起一个$last[i]$表示$i$节点所指向的失配边下一个出现的字符串结尾(专业术语叫后缀链接——suffix link),实现时直接在bfs求解fail数组时递推就好了。
对于本题,我们直接建好AC自动机,然后愉快的匹配,每次都累加一下失配边所指的完整字符串个数就好了,注意一下每个模式串重复出现只能算一次,所以累加完后要清除end标记。然后的话本题数据比较水,last数组优化并不明显,但是在加强版的模板题中优化效果还是可以的。(话说AC自动机并不难,以前咋不会呢?用下心体会,就好了!)
代码:
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
int n,trie[N][],tot,end[N],fail[N],last[N];
char s[N<<]; il void insert(char *s){
int len=strlen(s)-,p=,x;
For(i,,len){
x=s[i]-'a';
if(!trie[p][x])trie[p][x]=++tot;
p=trie[p][x];
}
end[p]++;
} il void bfs(){
queue<int>q;
For(i,,) if(trie[][i]) fail[trie[][i]]=,q.push(trie[][i]);
while(!q.empty()){
int u=q.front();q.pop();
For(i,,){
int v=trie[u][i];
if(v) fail[v]=trie[fail[u]][i],last[v]=end[fail[v]]?fail[v]:last[fail[v]],q.push(v);
else trie[u][i]=trie[fail[u]][i];
}
}
} il int find(char *s){
int ans=,len=strlen(s)-,p=;
For(i,,len){
p=trie[p][s[i]-'a'];
for(int j=p;j&&end[j]!=-;j=last[j]) ans+=end[j],end[j]=-;
}
return ans;
} int main(){
scanf("%d",&n);
For(i,,n) scanf("%s",s),insert(s);
bfs();
scanf("%s",s);
cout<<find(s);
return ;
}
P3808 【模板】AC自动机(简单版)的更多相关文章
- [模板][P3808]AC自动机(简单版)
Description: 求n个模式串中有几个在文本串中出现 Solution: 模板,详见代码: #include<bits/stdc++.h> using namespace std; ...
- luoguP3808[模板]AC自动机(简单版)
传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...
- 洛谷P3808 & P3796 AC自动机模板
题目:P3808:https://www.luogu.org/problemnew/show/P3808 P3796:https://www.luogu.org/problemnew/show/P37 ...
- 洛谷.3808/3796.[模板]AC自动机
题目链接:简单版,增强版 简单版: #include <cstdio> #include <cstring> const int N=1e6+5,S=26; char s[N] ...
- POJ 1625 Censored!(AC自动机->指针版+DP+大数)题解
题目:给你n个字母,p个模式串,要你写一个长度为m的串,要求这个串不能包含模式串,问你这样的串最多能写几个 思路:dp+AC自动机应该能看出来,万万没想到这题还要加大数...orz 状态转移方程dp[ ...
- luoguP3796[模板]AC自动机(加强版)
传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...
- Ring HDU - 2296 AC自动机+简单DP和恶心的方案输出
题意: 就是现在给出m个串,每个串都有一个权值,现在你要找到一个长度不超过n的字符串, 其中之前的m个串每出现一次就算一次那个字符串的权值, 求能找到的最大权值的字符串,如果存在多个解,输出最短的字典 ...
- 算法模板——AC自动机
实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...
- 模板 AC自动机
题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...
- 算法竞赛模板 AC自动机
AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...
随机推荐
- day 2 给程序传递参数
1.如何实现变化name name = "alex" print("欢迎%s前来指导学习"%name) 欢迎alex前来指导学习 2.sys.argv impo ...
- HTML5项目笔记10:使用HTML5 IndexDB设计离线数据库
之前的文章(http://www.cnblogs.com/wzh2010/archive/2012/05/22/2514017.html)里面描述了HTML5 离线数据存储的Web SQL,一个基于S ...
- egrep及扩展正则
模式:pattern 正则: grep:基本正则,查找速度慢 Extended grep:扩展正则 fgrep:fast grep,不支持正则,直接查找字符串,执行速度快 基本正则: . :任意单个字 ...
- Unity初探—SpaceShoot
Unity初探—SpaceShoot DestroyByBoundary脚本(C#) 在游戏中我们添加了一个Cube正方体,让他来作为游戏的边界.它是可以触发触发事件的(勾选Is Trigger),当 ...
- 微服务框架Dubbo与Springcloud的区别
微服务框架Dubbo与Springcloud的区别 微服务主要的优势如下: 1.降低复杂度 将原来偶合在一起的复杂业务拆分为单个服务,规避了原本复杂度无止境的积累.每一个微服务专注于单一功能,并通过定 ...
- 搭建hexo博客并部署到github上
hexo是由Node.js驱动的一款快速.简单且功能强大的博客框架,支持多线程,数百篇文章只需几秒即可生成.支持markdown编写文章,可以方便的生成静态网页托管在github上. 感觉不错. 前端 ...
- 使用Python客户端(redis-py)连接Redis--华为云DCS for Redis使用经验
使用Python连接Redis,需要先安装Python以及redis-py,以CentOS为例,介绍redis-py的客户端环境搭建. 第0步:准备工作 华为云上购买1台弹性云服务器ECS(我选了Ce ...
- 剑指offer-二叉树搜索树与双向链表25
题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. class Solution: def Convert(self, pRo ...
- [转载] RCNN/SPP/FAST RCNN/FASTER RCNN/YOLO/SSD算法简介
RCNN: RCNN(Regions with CNN features)是将CNN方法应用到目标检测问题上的一个里程碑,由年轻有为的RBG大神提出,借助CNN良好的特征提取和分类性能,通过Regio ...
- CryptoZombies学习笔记——Lesson4
第四课主要介绍payable函数相关. chapter1: payable修饰函数 以太坊允许同时调用函数和eth转账.msg.value显示发送到合约的以太币数,ether是内置整型数.如果函数没有 ...