题目背景

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

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

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

题目描述

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

输入输出格式

输入格式:

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

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

下面一行一个文本串。

输出格式:

一个数表示答案

输入输出样例

输入样例#1:

2
a
aa
aa
输出样例#1:

2

说明

subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;

subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;

也是模板,没什么么好说的,

只不过每次更新的时候是++,而不是=1!

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
const int MAXN=;
void read(int &n)
{
char c='+';int x=;bool flag=;
while(c<''||c>''){c=getchar();if(c=='-')flag=;}
while(c>=''&&c<=''){x=x*+c-;c=getchar();}
flag==?n=-x:n=x;
}
char s[MAXN];
char text[MAXN];
int n;
int ans=;
struct AC_Automata
{
int sz;
int ch[MAXN][];//trie树
int val[MAXN];// 记录是否有单词
int last[MAXN];
int f[MAXN];
int sigma_sz;
void Init()
{
memset(ch[],,sizeof(ch[]));
sz=;
sigma_sz=;
}
int idx(char c)
{
return c-'a';
}
void Insert(char *s,int pos)
{
int l=strlen(s); int now=;
for(int i=;i<l;i++)
{
int c=idx(s[i]);
if(!ch[now][c])
{
memset(ch[sz],,sizeof(ch[sz]));
val[sz]=;
ch[now][c]=sz++;
}
now=ch[now][c];
}
val[now]++;//一个单词的结束
}
void getfail()
{
f[]=;
queue<int>q;
for(int i=;i<sigma_sz;i++)
{
int u=ch[][i];
if(u)// 此处有单词出现
{
f[u]=;// 连向根节点
q.push(u);
last[u]=;// 上一个出现的单词一定是根节点
// 上面两条语句没什么卵用,只是为了帮助理解AC自动机的含义
}
}
while(!q.empty())
{
int p=q.front();q.pop();
for(int i=;i<sigma_sz;i++)
{
int u=ch[p][i];
if(!u)//没有孩子
{
ch[p][i]=ch[f[p]][i];// 补上一条不存在的边,减少查找次数
continue;
}
q.push(u);
int v=f[p];// 找到它的失陪指针
f[u]=ch[v][i];//因为我们在上面补上了一条不存在边,所以他一定存在孩子
last[u]=val[f[u]] ? f[u] : last[f[u]];
//判断下是不是单词结尾 是, 不是
}
}
}
int ok(int pos)
{
if(val[pos])
{
ans+=val[pos];
val[pos]=;
ok(last[pos]);
}
}
void find(char *s)// 查找模式串
{
int l=strlen(s);
int j=;// 当前节点的编号
for(int i=;i<l;i++)
{
int c=idx(s[i]);
while(j&&!ch[j][c])
j=f[j];// 顺着失配边走
j=ch[j][c]; // 取到儿子
if(val[j])
ok(j);// 找到一个单词
else if(last[j])
ok(last[j]);// 当前节点不行就看看上一个单词出现的位置行不行
}
}
}ac;
int main()
{
scanf("%d",&n);
ac.Init();
for(int i=;i<=n;i++)
{
scanf("%s",s);
ac.Insert(s,i);
}
ac.getfail();
scanf("%s",text);
ac.find(text);
printf("%d\n",ans);
return ;
}

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

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

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

  2. [算法模版]AC自动机

    [算法模版]AC自动机 基础内容 板子不再赘述,OI-WIKI有详细讲解. \(query\)函数则是遍历文本串的所有位置,在文本串的每个位置都沿着\(fail\)跳到根,将沿途所有元素答案++.意义 ...

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

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

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

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

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

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

  6. 小明系列故事――女友的考验 HDU - 4511 AC自动机+简单DP

    题意:自己看题目,中文体面. 题解: 把所有不能走的路径放入AC自动机中. 然后DP[i][j]表示走到 i 这个点,且位于AC自动机 j 这个节点最短距离 然后直接DP即可.注意一点会爆int #i ...

  7. Walk Through Squares HDU - 4758 AC自动机+简单状压DP

    题意:给你两个串,求用m个R,n个D能组成多少个包含这两个串 题解:先构造一个AC自动机记录每个状态包含两个串的状态, 状态很容易定义 dp[i][j][k][status]表示在AC自动机K这个节点 ...

  8. Censored! - POJ 1625(ac自动机+简单dp+高精度运算)

    题目大意:首先给一个字符集合,这个集合有N个字符,然后需要一个长度为M的句子,但是据子里面不能包含的串有P个,每个串里面的字符都是有字符集和里面的字符构成的,现在想知道最多能构造多少个不重复的句子. ...

  9. AC自动机例题

    P3808 [模板]AC自动机(简单版) [题目描述] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. #include<bits/stdc++.h> using name ...

  10. 【AC自动机】AC自动机

    Definition & Solution AC自动机是一种多模式串的字符串匹配数据结构,核心在于利用 fail 指针在失配时将节点跳转到当前节点代表字符串的最长后缀子串. 首先对 模式串 建 ...

随机推荐

  1. python tips:小整数对象池与字符串intern

    本文为is同一性运算符的详细解释.is用于判断两个对象是否为同一个对象,具体来说是两个对象在内存中的位置是否相同. python为了提高效率,节省内存,在实现上大量使用了缓冲池技术和字符串intern ...

  2. python tips:作为dict的key的类

    Python的dict由hash实现,解决hash冲突的方法是二次探查法.hash值相同的元素会形成链表.所以dict在查找key时,首先获取hash值,直接得到链表的表头:而后在链表中查找等于key ...

  3. 【转载】java的常见类型转换

    //Int型数字转换成String int num1=123456; //方法1 String str1=num1+""; System.out.println(str1); // ...

  4. Log4net日志发布到服务器上日志无法写入

    log4net在本地执行时候,日志正常写入,但是发布到服务器上的时候,日志就无法正常写入 解决方案: 1.文件权限 在发布到服务器上的时候,可能文件没有写入权限,导致日志无法正常写入 打开IIS 找到 ...

  5. 家谱(gen)——洛谷P2814

    #include <iostream> #include <string> #include <map> using namespace std; map < ...

  6. [poj1325] Machine Schedule (二分图最小点覆盖)

    传送门 Description As we all know, machine scheduling is a very classical problem in computer science a ...

  7. 将RedHat的yum更换为CentOS的yum

    CentOS6.8 脚本: #安装yum所需的包已经下载到本地 #!/bin/bashrpm -qa | grep yum | xargs rpm -e --nodepsrm -rf /etc/yum ...

  8. Spring MVC学习总结(4)——SpringMVC权限管理

    1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet.     DispatcherServl ...

  9. jvm学习-垃圾回收算法(三)

     垃圾回收算法  引用计数法 比较古老的一种垃圾回收算法.在java的GC并没有采用 增加一个引用 引用+1 减少一个引用引用减一 每次清除引用为0的的对象 缺点:不能回收循环引用的垃圾对象 标记清除 ...

  10. hdu 1250 简单大整数加法

    #include<stdio.h> #include<string.h> #define N 3100 int a[N],b[N],c[N],d[N],e[N]; int ma ...