并不对劲的AC自动机
这像是能解决所有问题的样子(并不)。AC自动机之所以叫AC自动机是因为它能解决所有AC自动机的题。
其实只能解决的是很多模式串匹配一个母串的问题。
把kmp中的next数组得到下一次跳转的位置看成特殊的边,把字符串看成链,就会得到一个特殊的图。
一个点u的next连向点v对应的字符串是u最长的后缀,把这个图套用到很多个模式串组成的trie上。
对于点u能走到的节点ch[u][i],相当于在u对应的字符串后补了一个字符i。那么点u的next连向的点v对应的字符串后面再补一个字符i就是点ch[u][i]的next。有时并没有ch[v][i],那么就要找v的next也就是更短的后缀。要是一直找不到,就只能连向0号点(空串)了。算next是一定要用bfs,不然会出现要走u的next却发现u的next还没有被算出的尴尬情况。
匹配时,如果没有ch[u][i]就要走u的next。还要注意的是,能走到u说明也能走到u的next、u的next的next、u的next的next的next等,要把这些点的值也加上。这样不会TLE吗?想必是不会的。要想知道一堆字符串中有多少个是某个串的子串,走到每个字符串结尾代表的节点时,只能统计一次。那么在统计时可以进行标记,被标记的点就不走了。又因为当一个点被标记时,它的next、它的next的next等都已经被统计过了,所以当顺着next统计的时候,发现一个被标记的点就可以停止了。自动机上的每一个点只会走到一次,所以并不会TLE。
考虑next很麻烦?当ch[u][i]==0时,令ch[u][i]=next!
#include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iomanip> #include<iostream> #include<map> #include<queue> #include<stack> #include<vector> #define maxn 1000010 #define rep(i,x,y) for(register int i=(x);i<=(y);i++) #define dwn(i,x,y) for(register int i=(x);i>=(y);i--) #define vv ch[u][i] using namespace std; inline int read() {int x=0,f=1;char ch=getchar();while(isdigit(ch)==0 && ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*f; } inline void write(int x) {int f=0;char ch[20];if(!x){puts("0");return;}if(x<0){putchar('-');x=-x;}while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar('\n'); } int ch[maxn][30],val[maxn],fail[maxn],cnt=0,n,len; char s[maxn]; int gx(char c){return c-'a';} void build() {int u=0;rep(i,0,len-1){if(!ch[u][gx(s[i])])ch[u][gx(s[i])]=++cnt;u=ch[u][gx(s[i])];}val[u]++; } void getfail() {fail[0]=0;queue<int >q;rep(i,0,25)if(ch[0][i])q.push(ch[0][i]),fail[ch[0][i]]=0;while(!q.empty()){int u=q.front();q.pop();rep(i,0,25){if(vv)q.push(vv),fail[vv]=ch[fail[u]][i];else vv=ch[fail[u]][i];}} } int getans() {int ans=0,u=0;rep(i,0,len-1){u=ch[u][gx(s[i])];for(int j=u;j&&val[j]!=-1;j=fail[j])ans+=val[j],val[j]=-1;}return ans; } int main() {n=read();rep(i,1,n)scanf("%s",s),len=strlen(s),build();getfail();scanf("%s",s),len=strlen(s);write(getans());return 0; }
View Code
#include<set> #include<map> #include<cmath> #include<queue> #include<stack> #include<ctime> #include<string> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define LL long long #define MAXN 1000+1000000 #define INF 2147483647using namespace std; inline int read(){int x=0,f=1; char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;for(;isdigit(ch);ch=getchar())x=ch-'0'+(x<<3)+(x<<1);return x*f; }char str[MAXN]; struct ACAutomata{int ch[MAXN][31],val[MAXN],size;queue<int>Q; int fail[MAXN],vis[MAXN];void insert(){int cur=0,len=strlen(str);for(int i=0;i<len;i++){if(ch[cur][str[i]-'a'])cur=ch[cur][str[i]-'a'];else ch[cur][str[i]-'a']=++size,cur=size;}val[cur]++; return ;}void calc(){while(!Q.empty()){int u=Q.front(); Q.pop();for(int i=0;i<26;i++){if(!ch[u][i])continue;int cur=fail[u]; Q.push(ch[u][i]);while(!ch[cur][i]&&cur)cur=fail[cur];fail[ch[u][i]]=ch[cur][i];}}return ;}int solve(){int cur=0,ans=0,len=strlen(str),pos=0;while(pos<len){for(int i=cur;!vis[i]&&i!=0;i=fail[i])ans+=val[i],vis[i]=1; if(ch[cur][str[pos]-'a'])cur=ch[cur][str[pos]-'a'];else {cur=fail[cur];while(!ch[cur][str[pos]-'a']&&cur)cur=fail[cur];cur=ch[cur][str[pos]-'a'];}for(int i=cur;!vis[i]&&i!=0;i=fail[i])ans+=val[i],vis[i]=1; pos++;}return ans;} }T;int main(){int n=read();for(int i=1;i<=n;i++){scanf("%s",str);T.insert();}for(int i=0;i<=25;i++)if(T.ch[0][i])T.Q.push(T.ch[0][i]);T.calc(); scanf("%s",str); printf("%d",T.solve());return 0; }
View Code
别人一般把这种并不对劲的next称为失配边、fail之类的。
刚刚说过这是一个特殊的图,因为每个点只会连出一条失配边,所有失配边也组成了一棵树。
这样树上的某些坑人操作也可以在AC自动机上做了。。。
转载于:https://www.cnblogs.com/xzyf/p/8244527.html
并不对劲的AC自动机相关推荐
- Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现
多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...
- 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组
[BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...
- AC自动机算法及模板
AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报 分类: AC自动机(1) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...
- Keywords Search AC自动机QAQ
AC自动机,一直以来都以为是一个非常高大上的算法,其实它还真的挺高大上的. 首先来说,ac自动机的思想与kmp类似,需要自己模拟来理解. 给两个博客: http://www.cppblog.com/m ...
- 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法
文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...
- 【Luogu3041】视频游戏的连击(AC自动机,动态规划)
题面链接 题解 首先构建出AC自动机 然后在AC自动机上面跑DP 转移很显然从Trie树的节点跳到他的儿子节点 但是要注意一个问题, 在计算的时候,每一个节点加入后能够 造成的贡献 要加上他的子串的贡 ...
- HDU2896(AC自动机模版题)
AC自动机模版题: 方法一:超时 #include<iostream> #include<algorithm> #include<cstring> #include ...
- HDU2222(AC自动机模版题)
AC自动机是Trie树和KMP的结合物,但是其实KMP在这里体现了思想,而Trie树才是最重要的,要想学懂AC自动机,学习Trie树是必须的,这些是自己在学习AC自动机的个人看法,我也是在网上学习了大 ...
- AC自动机 + 概率dp + 高斯消元 --- HDU 5955 or 2016年沈阳icpc H [AC自动机 + 概率dp + 高斯消元]详解
题目链接 题目大意: 就是有NNN个人,每个人都会猜一个长度为LLL的只包含{1,2,3,4,5,6}\{1,2,3,4,5,6\}{1,2,3,4,5,6}的序列,现在裁判开始投掷骰子,并且把每次的 ...
- P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)
P5357 [模板]AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数) 传送门 形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边:本质 ...
最新文章
- 世界无烟日丨如何科学戒烟?
- 图解TC++3.0开发教程
- Btree索引和Hash索引
- 【DP】[NOI2013]书法家
- python怎么用lambda和map函数_Python之lambda匿名函数及map和filter的用法
- 【C】Natasha V1.3.6.0 的升级日志
- android页面布局更改,使用setContentView的方式更换布局文件从而更换界面
- 【组件化开发】前端进阶篇之如何编写可维护可升级的代码
- 风控模型中的变量替换
- java中的设计模式
- UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xb4 in position 176: in xxxx
- 商城项目html pc,Vue实战篇(PC端商城项目)
- python 离散点 等高线_飞时达软件离散点高程、等高线高程、特征线高程等检查与处理...
- 「 数学模型 」“使用SPSS软件主成分分析”实例
- 开源数据库管理系统现在比商业产品更受欢迎
- 热插拔技术详解(上)
- 教你使用Box2d制作用蜡笔手绘物体的效果(一)
- SQL Server 2005“备份集中的数据库备份与现有的数据库不同”解决方法 详细出处参考:http://www.jb51.net/article/19233.htm
- 富士相机设置传原图_富士X-S10相机传图必看!原创完美解决PC互传图片问题
- FineReport填报--批量删除
热门文章
- smale学习之数学表达式(day5)
- 分析uint8_t\uint_16_t\uint32_t\uint64_t
- pycharm Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon run
- 【两种方式】用python和ENVI画出高光谱遥感影像的3D立体图
- 书接上文——python实现感知分类器模型分类过程动态可视化
- php $delaytime /= $delaytime,计算PHP / MySQL / JavaScript系统中的时差
- 中文文档保存到mysql_mysql 中文 存储
- 【Django 2021年最新版教程4】为项目添加资源文件(css,js,image)
- 微信小程序 云函数 Date时间不对+8小时 设置北京时间
- form表单提交大量input,php接收不全