这像是能解决所有问题的样子(并不)。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自动机相关推荐

  1. Aho-Corasick 多模式匹配算法(AC自动机) 的算法详解及具体实现

    多模式匹配 多模式匹配就是有多个模式串P1,P2,P3-,Pm,求出所有这些模式串在连续文本T1-.n中的所有可能出现的位置. 例如:求出模式集合{"nihao","ha ...

  2. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  3. AC自动机算法及模板

    AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报  分类: AC自动机(1)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...

  4. Keywords Search AC自动机QAQ

    AC自动机,一直以来都以为是一个非常高大上的算法,其实它还真的挺高大上的. 首先来说,ac自动机的思想与kmp类似,需要自己模拟来理解. 给两个博客: http://www.cppblog.com/m ...

  5. 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法

    文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...

  6. 【Luogu3041】视频游戏的连击(AC自动机,动态规划)

    题面链接 题解 首先构建出AC自动机 然后在AC自动机上面跑DP 转移很显然从Trie树的节点跳到他的儿子节点 但是要注意一个问题, 在计算的时候,每一个节点加入后能够 造成的贡献 要加上他的子串的贡 ...

  7. HDU2896(AC自动机模版题)

    AC自动机模版题: 方法一:超时 #include<iostream> #include<algorithm> #include<cstring> #include ...

  8. HDU2222(AC自动机模版题)

    AC自动机是Trie树和KMP的结合物,但是其实KMP在这里体现了思想,而Trie树才是最重要的,要想学懂AC自动机,学习Trie树是必须的,这些是自己在学习AC自动机的个人看法,我也是在网上学习了大 ...

  9. 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}的序列,现在裁判开始投掷骰子,并且把每次的 ...

  10. P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)

    P5357 [模板]AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数) 传送门 形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边:本质 ...

最新文章

  1. 世界无烟日丨如何科学戒烟?
  2. 图解TC++3.0开发教程
  3. Btree索引和Hash索引
  4. 【DP】[NOI2013]书法家
  5. python怎么用lambda和map函数_Python之lambda匿名函数及map和filter的用法
  6. 【C】Natasha V1.3.6.0 的升级日志
  7. android页面布局更改,使用setContentView的方式更换布局文件从而更换界面
  8. 【组件化开发】前端进阶篇之如何编写可维护可升级的代码
  9. 风控模型中的变量替换
  10. java中的设计模式
  11. UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xb4 in position 176: in xxxx
  12. 商城项目html pc,Vue实战篇(PC端商城项目)
  13. python 离散点 等高线_飞时达软件离散点高程、等高线高程、特征线高程等检查与处理...
  14. 「 数学模型 」“使用SPSS软件主成分分析”实例
  15. 开源数据库管理系统现在比商业产品更受欢迎
  16. 热插拔技术详解(上)
  17. 教你使用Box2d制作用蜡笔手绘物体的效果(一)
  18. SQL Server 2005“备份集中的数据库备份与现有的数据库不同”解决方法 详细出处参考:http://www.jb51.net/article/19233.htm
  19. 富士相机设置传原图_富士X-S10相机传图必看!原创完美解决PC互传图片问题
  20. FineReport填报--批量删除

热门文章

  1. smale学习之数学表达式(day5)
  2. 分析uint8_t\uint_16_t\uint32_t\uint64_t
  3. pycharm Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon run
  4. 【两种方式】用python和ENVI画出高光谱遥感影像的3D立体图
  5. 书接上文——python实现感知分类器模型分类过程动态可视化
  6. php $delaytime /= $delaytime,计算PHP / MySQL / JavaScript系统中的时差
  7. 中文文档保存到mysql_mysql 中文 存储
  8. 【Django 2021年最新版教程4】为项目添加资源文件(css,js,image)
  9. 微信小程序 云函数 Date时间不对+8小时 设置北京时间
  10. form表单提交大量input,php接收不全