题目背景

这是一道简单的AC自动机模板题。

用于检测正确性以及算法常数。

为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。

管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意

题目描述

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

输入输出格式

输入格式:

第一行一个n,表示模式串个数;

下面n行每行一个模式串;

下面一行一个文本串。

输出格式:

一个数表示答案

输入输出样例

输入样例#1:

  1. 2
  2. a
  3. aa
  4. aa
输出样例#1:

  1. 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自动机并不难,以前咋不会呢?用下心体会,就好了!)

代码:

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define ll long long
  4. #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
  5. #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
  6. using namespace std;
  7. const int N=;
  8. int n,trie[N][],tot,end[N],fail[N],last[N];
  9. char s[N<<];
  10.  
  11. il void insert(char *s){
  12. int len=strlen(s)-,p=,x;
  13. For(i,,len){
  14. x=s[i]-'a';
  15. if(!trie[p][x])trie[p][x]=++tot;
  16. p=trie[p][x];
  17. }
  18. end[p]++;
  19. }
  20.  
  21. il void bfs(){
  22. queue<int>q;
  23. For(i,,) if(trie[][i]) fail[trie[][i]]=,q.push(trie[][i]);
  24. while(!q.empty()){
  25. int u=q.front();q.pop();
  26. For(i,,){
  27. int v=trie[u][i];
  28. if(v) fail[v]=trie[fail[u]][i],last[v]=end[fail[v]]?fail[v]:last[fail[v]],q.push(v);
  29. else trie[u][i]=trie[fail[u]][i];
  30. }
  31. }
  32. }
  33.  
  34. il int find(char *s){
  35. int ans=,len=strlen(s)-,p=;
  36. For(i,,len){
  37. p=trie[p][s[i]-'a'];
  38. for(int j=p;j&&end[j]!=-;j=last[j]) ans+=end[j],end[j]=-;
  39. }
  40. return ans;
  41. }
  42.  
  43. int main(){
  44. scanf("%d",&n);
  45. For(i,,n) scanf("%s",s),insert(s);
  46. bfs();
  47. scanf("%s",s);
  48. cout<<find(s);
  49. return ;
  50. }

P3808 【模板】AC自动机(简单版)的更多相关文章

  1. [模板][P3808]AC自动机(简单版)

    Description: 求n个模式串中有几个在文本串中出现 Solution: 模板,详见代码: #include<bits/stdc++.h> using namespace std; ...

  2. luoguP3808[模板]AC自动机(简单版)

    传送门 ac自动机模板题,裸的多串匹配 代码: #include<cstdio> #include<iostream> #include<algorithm> #i ...

  3. 洛谷P3808 & P3796 AC自动机模板

    题目:P3808:https://www.luogu.org/problemnew/show/P3808 P3796:https://www.luogu.org/problemnew/show/P37 ...

  4. 洛谷.3808/3796.[模板]AC自动机

    题目链接:简单版,增强版 简单版: #include <cstdio> #include <cstring> const int N=1e6+5,S=26; char s[N] ...

  5. POJ 1625 Censored!(AC自动机->指针版+DP+大数)题解

    题目:给你n个字母,p个模式串,要你写一个长度为m的串,要求这个串不能包含模式串,问你这样的串最多能写几个 思路:dp+AC自动机应该能看出来,万万没想到这题还要加大数...orz 状态转移方程dp[ ...

  6. luoguP3796[模板]AC自动机(加强版)

    传送门 ac自动机模板,可能我写的ac自动机是有点问题的,所以跑的有些慢 暴力跳fail统计 代码: #include<cstdio> #include<iostream> # ...

  7. Ring HDU - 2296 AC自动机+简单DP和恶心的方案输出

    题意: 就是现在给出m个串,每个串都有一个权值,现在你要找到一个长度不超过n的字符串, 其中之前的m个串每出现一次就算一次那个字符串的权值, 求能找到的最大权值的字符串,如果存在多个解,输出最短的字典 ...

  8. 算法模板——AC自动机

    实现功能——输入N,M,提供一个共计N个单词的词典,然后在最后输入的M个字符串中进行多串匹配(关于AC自动机算法,此处不再赘述,详见:Aho-Corasick 多模式匹配算法.AC自动机详解.考虑到有 ...

  9. 模板 AC自动机

    题目描述 有$N$ 个由小写字母组成的模式串以及一个文本串$T$ .每个模式串可能会在文本串中出现多次.你需要找出哪些模式串在文本串$T$ 中出现的次数最多. 输入输出格式 输入格式: 输入含多组数据 ...

  10. 算法竞赛模板 AC自动机

    AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...

随机推荐

  1. Qt 学习之路 2

    Qt 学习之路 2 | DevBean Tech World Qt 学习之路 2 Qt 学习之路 2 目录

  2. ruby 技巧 根据函数的返回

    一般语言中,函数必须有返回值,即要带个return关键字.但在ruby中,return不是必须的,如果不写会默认返回最终计算的结果.举例 def add(a,b) # 省去了return a + b ...

  3. 在ubuntu安装python, theano, keras , Spearmint, Mongodb

    系统配置: Ubuntu 14 (其他系统也差不多如下操作) 1. 通过anaconda安装 python 地址: https://www.continuum.io/downloads#linux 2 ...

  4. gitlab-登录账户遇到ERROR: Permission to XXX.git denied to user报错怎么办

    碰到这个问题就意味着没有访问账户的权限,没有把访问电脑与访问账户用ssh_key关联起来,解决流程: 1.查看本地是否有ssh_key 笔者用的是git bash来输入命令 ls -al ~/.ssh ...

  5. 第四篇 与Flask相关的插件(flask-session、wtforms)

    公司中使用SQL的种方式: 1. 写Django:ORM(关系对象映射), 2. 写Flask和其他:有两种方式: (1) 原生SQL:使用原生SQL有两种选择: A. pymysql (python ...

  6. TPO-11 C2 Work for the biology committee

    committee 委员会 representative 代表 department secretary 系里的秘书 applicant 申请人 TPO-11 C2 Work for the biol ...

  7. 前端开发工程师 - 01.页面制作 - 第1章.Photoshop切图

    第1章--Photoshop切图 工具.面板.视图 什么是切图? 1. 从设计稿(.psd)中切出网络素材,如按钮.图标.logo.背景图等 2. 编写代码,在代码中使用图片,生成静态页面 --给网页 ...

  8. mybatis interceptor 处理查询参数及查询结果

    拦截器:拦截update,query方法,处理查询参数及返回结果. /** * Created by windwant on 2017/1/12. */ @Intercepts({ @Signatur ...

  9. 统计hive库表在具体下所有分区大小

    1 查询具体表分区大小,以字节展示 hadoop fs -du /user/hive/warehouse/treasury.db/dm_user_excercise > dm_user_exce ...

  10. TW实习日记:第18天

    今天的bug没有那么多了,都是些小bug,一下就改好了.或者是接口那边数据返回的有问题,通知一下同事就ok了.主要今天是在赶功能进度,然而有一个功能模块需求里并没有写,实在是不知道要做成什么样子,真的 ...