ac自动机算法正确性还没有理解,算法导论也看不懂。。等懂了回来发算法专题。

 #include <cstdio>
#include <cstring>
using namespace std; const int maxn=1e6+; int n;
char s[maxn]; class AC{
public:
struct node{
node *son[], *fail;
int mark;
}root, *now, *nowson, *p;
AC(){}
void insert(char *s, int len){ //trie,没什么好说的
now=&root;
int v;
for (int i=; i<len; ++i){
v=s[i]-'a';
if (!now->son[v]) now->son[v]=new node();
now=now->son[v];
}
++now->mark;
}
void get_fail(){ //建立失败指针
int head=, tail=;
q[head]=&root;
while (head<tail){ //宽搜
now=q[head];
for (int i=; i<; ++i) //遍历每个儿子
if (now->son[i]){
for (p=now->fail; p&&!p->son[i]; p=p->fail); //通过父亲来找失败指针
//p是0,意味着连root都不行,那只能去root
now->son[i]->fail=(p?p->son[i]:&root);
q[tail++]=now->son[i];
} //else now->son[i]=now->fail->son[i]; //如果没有这个子节点,意味着肯定失配
++head;
}
}
int count(char *s, int len){ //计算有多少个串出现
int ans=;
now=&root;
int v;
for (int i=; i<len; ++i){
//确定适配的树的结点位置
for (v=s[i]-'a'; now&&!now->son[v]; now=now->fail);
now=now?now->son[v]:&root; //如果一直到根还不匹配,那就跳到根
//对于一个匹配串的所有后缀检查
//如果这里ans没设置为-1,那就是求出现次数之和
for (p=now; p&&~p->mark; p=p->fail) {
ans+=p->mark;
p->mark=-;
}
}
return ans;
}
private:
node *q[maxn], head, tail;
}; AC ac; int main(){
scanf("%d", &n);
for (int i=; i<n; ++i){
scanf("%s", s);
int t=strlen(s);
ac.insert(s, t);
}
ac.get_fail();
scanf("%s", s);
printf("%d\n", ac.count(s, strlen(s)));
return ;
}
 #include <cstdio>
#include <cstring>
using namespace std; const int maxn=, maxl1=, maxl2=1e6+; int n, cnt, ans[maxn];
char p[maxn][maxl1];
char t[maxl2]; struct node{
node *son[], *fail;
int id, mark;
}*mem[maxn*maxl1];
class AC{
public:
node *root, *now, *nowson, *p;
AC(){ root=new node(); }
void fresh(){
cnt=;
delete root;
root=new node();
for (int i=; i<memlen; ++i) delete mem[i];
memlen=;
}
void insert(char *s, int len){ //trie,没什么好说的
now=root;
int v;
for (int i=; i<len; ++i){
v=s[i]-'a';
if (!now->son[v]) {
now->son[v]=new node();
mem[memlen++]=now->son[v];//内存回收表
}
now=now->son[v];
}
//如果不去重,这里写成等于1
now->id=cnt++;
++now->mark;
}
void get_fail(){ //建立失败指针
int head=, tail=;
q[head]=root;
while (head<tail){ //宽搜
now=q[head];
for (int i=; i<; ++i) //遍历每个儿子
if (now->son[i]){
for (p=now->fail; p&&!p->son[i]; p=p->fail); //通过父亲来找失败指针
//p是0,意味着连root都不行,那只能去root
now->son[i]->fail=(p?p->son[i]:root);
q[tail++]=now->son[i];
} //else now->son[i]=now->fail->son[i]; //如果没有这个子节点,意味着肯定失配
++head;
}
}
void count(char *s, int len){ //计算有多少个串出现
now=root;
int v;
for (int i=; i<len; ++i){
//确定适配的树的结点位置
for (v=s[i]-'a'; now&&!now->son[v]; now=now->fail);
now=now?now->son[v]:root; //如果一直到根还不匹配,那就跳到根
//对于一个匹配串的所有后缀检查
//如果这里ans没设置为-1,那就是求出现次数之和
for (p=now; p&&~p->mark; p=p->fail) {
ans[p->id]+=p->mark;
//p->mark=-1;
}
}
}
private:
node *q[maxn*maxl1]; //这里忘记加了
int memlen;
}; AC ac; int main(){
scanf("%d", &n);
while (n){
memset(ans, , sizeof(ans));
for (int i=; i<n; ++i){
scanf("%s", p[i]);
int t=strlen(p[i]);
ac.insert(p[i], t);
}
ac.get_fail();
scanf("%s", t);
ac.count(t, strlen(t));
int maxm=;
for (int i=; i<n; ++i)
if (ans[i]>maxm) maxm=ans[i];
printf("%d\n", maxm);
for (int i=; i<n; ++i)
if (ans[i]==maxm) printf("%s\n", p[i]);
scanf("%d", &n);
ac.fresh();
}
return ;
}

ac自动机俩模板的更多相关文章

  1. AC自动机 (模板)

    AC自动机是用来干什么的: AC自动机是用来解决多模匹配问题,例如有单词s1,s2,s3,s4,s5,s6,问:在文本串ss中有几个单词出现过,类似. AC自动机实现这个功能需要三个部分: 1.将所有 ...

  2. [hdu2222]ac自动机(模板)

    题意:一个文本串+多个模板串的匹配问题 思路:裸的ac自动机. #pragma comment(linker, "/STACK:10240000,10240000") #inclu ...

  3. HDOJ-3065(AC自动机+每个模板串的出现次数)

    病毒侵袭持续中 HDOJ-3065 第一个需要注意的是树节点的个数也就是tree的第一维需要的空间是多少:模板串的个数*最长模板串的长度 一开始我的答案总时WA,原因是我的方法一开始不是这样做的,我是 ...

  4. luogu AC自动机(模板)

    完全忘了AC自动机怎么写了qwq,更别说AC自动机上DP了. 今天就好好地学习字符串好了qwq 提一下AC自动机的时间复杂度--设n是模式串的个数,m是文本串的长度,l是模式串的平均长度,那么它的时间 ...

  5. AC自动机(模板) LUOGU P3808

    传送门 解题思路 AC自动机,是解决多模匹配问题的算法,是字典树与kmp结合的算法,可以解决许多子串在文本串中出现的次数等信息.关键是实现一个fail指针,是指向更靠上的前缀相同字母,从而可以实现在文 ...

  6. AC自动机(模板+例题)

    首先要明白AC自动机是干什么的: AC自动机其实就是一种多模匹配算法,那么你可能会问什么叫做多模匹配算法.下面是我对多模匹配的理解,与多模与之对于的是单模,单模就是给你一个单词,然后给你一个字符串,问 ...

  7. AC自动机及其模板

    模板 #include<queue> #include<stdio.h> #include<string.h> using namespace std; ; ; ; ...

  8. AC自动机(模板)

    #include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> ...

  9. hdu 2222 ac自动机更新模板 for onSite contest

    http://acm.split.hdu.edu.cn/showproblem.php?pid=2222 #include <cstdio> #include <cstdlib> ...

随机推荐

  1. 分享知识-快乐自己:Caused by: org.hibernate.tool.schema.extract.spi.SchemaExtractionException: More than one table found in namespace (, ) : Dept (XXX)

    在命名空间(,)中找到多个表 - SchemaExtractionException? 问题: 尝试在Java应用程序中使用Hibernate将一些值保存到表中时,我一直面临着这个奇怪的异常. 但是, ...

  2. Memcached 分布式缓存实现原理简介

    摘要 在高并发环境下,大量的读.写请求涌向数据库,此时磁盘IO将成为瓶颈,从而导致过高的响应延迟,因此缓存应运而生.无论是单机缓存还是分布式缓存都有其适应场景和优缺点,当今存在的缓存产品也是数不胜数, ...

  3. lombok_学习_00_资源帖

    二.参考资料 Java界的神器-使用Lombok来消除你的冗余代码量 Lombok:让JAVA代码更优雅 Lombok开发指南

  4. javascript-JQuery样式篇(一)

    轻量级的JavaScript库,核心依然是JavaScript,不仅兼容了CSS3,还兼容了各种浏览器 强大的选择器,完善的事件机制,出色的Ajax封装,丰富的UI 进入官方网站获取最新的版本 htt ...

  5. 关于android 图片加载优化

    android应用对图片处理算是比较频繁的了,尤其是在程序加载大量图片和高分辨率图片时,最容易产生oom异常,下面是个人平时一些省内存加载方法 方法一: public Bitmap decodeFil ...

  6. BZOJ5323 JXOI2018 游戏

    传送门 这是我见过的为数不多的良心九怜题之一. 题目大意 有一堆屋子,编号为$l,l+1...r-1,r$,你每次会走入一个没走入过的房子,然后这个房子以及编号为这个房子编号的倍数的房子就会被自动标记 ...

  7. 每天一个linux命令(6):rm命令

    版权声明更新:2017-05-10博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1文章介绍 本文介绍了Linux下面的rm命令. 2 开 ...

  8. ECMAScript基本函数、概念区分总结

    1.使用Number()和parseInt() parseFloat()转换区别. 详见<JavaScript高级程序设计>P30 Number()可以针对任何类型. parseInt() ...

  9. Bellman-Ford算法及其队列优化(SPFA)

    一.算法概述 Bellman-Ford算法解决的是一般情况下的单源最短路径问题.所谓单源最短路径问题:给定一个图G=(V,E),我们希望找到从给定源结点s属于V到每个结点v属于V的最短路径.单源最短路 ...

  10. 机器学习:Jupyter Notebook中Matplotlib的使用

    一.matplotlib绘制折线图 matplotlib绘图的实质是折线图,将所有的点用直线连接起来,由于距离比较密,看起来像是个平滑的曲线: import matplotlib as mpl:加载m ...