P3808 【模版】AC自动机(简单版)

题目背景

这是一道简单的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!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<map>
  8 using namespace std;
  9 const int MAXN=1000001;
 10 void read(int &n)
 11 {
 12     char c=‘+‘;int x=0;bool flag=0;
 13     while(c<‘0‘||c>‘9‘){c=getchar();if(c==‘-‘)flag=1;}
 14     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-48;c=getchar();}
 15     flag==1?n=-x:n=x;
 16 }
 17 char s[MAXN];
 18 char text[MAXN];
 19 int n;
 20 int ans=0;
 21 struct AC_Automata
 22 {
 23     int sz;
 24     int ch[MAXN][26];//trie树
 25     int val[MAXN];// 记录是否有单词
 26     int last[MAXN];
 27     int f[MAXN];
 28     int sigma_sz;
 29     void Init()
 30     {
 31         memset(ch[0],0,sizeof(ch[0]));
 32         sz=1;
 33         sigma_sz=26;
 34     }
 35     int idx(char c)
 36     {
 37         return c-‘a‘;
 38     }
 39     void Insert(char *s,int pos)
 40     {
 41         int l=strlen(s); int now=0;
 42         for(int i=0;i<l;i++)
 43         {
 44             int c=idx(s[i]);
 45             if(!ch[now][c])
 46             {
 47                 memset(ch[sz],0,sizeof(ch[sz]));
 48                 val[sz]=0;
 49                 ch[now][c]=sz++;
 50             }
 51             now=ch[now][c];
 52         }
 53         val[now]++;//一个单词的结束
 54     }
 55     void getfail()
 56     {
 57         f[0]=0;
 58         queue<int>q;
 59         for(int i=0;i<sigma_sz;i++)
 60         {
 61             int u=ch[0][i];
 62             if(u)// 此处有单词出现
 63             {
 64                 f[u]=0;// 连向根节点
 65                 q.push(u);
 66                 last[u]=0;// 上一个出现的单词一定是根节点
 67                 // 上面两条语句没什么卵用,只是为了帮助理解AC自动机的含义
 68             }
 69         }
 70         while(!q.empty())
 71         {
 72             int p=q.front();q.pop();
 73             for(int i=0;i<sigma_sz;i++)
 74             {
 75                 int u=ch[p][i];
 76                 if(!u)//没有孩子
 77                 {
 78                     ch[p][i]=ch[f[p]][i];// 补上一条不存在的边,减少查找次数
 79                     continue;
 80                 }
 81                 q.push(u);
 82                 int v=f[p];// 找到它的失陪指针
 83                 f[u]=ch[v][i];//因为我们在上面补上了一条不存在边,所以他一定存在孩子
 84                 last[u]=val[f[u]] ? f[u] : last[f[u]];
 85                 //判断下是不是单词结尾  是, 不是
 86             }
 87         }
 88     }
 89     int ok(int pos)
 90     {
 91         if(val[pos])
 92         {
 93             ans+=val[pos];
 94             val[pos]=0;
 95             ok(last[pos]);
 96         }
 97     }
 98     void find(char *s)// 查找模式串
 99     {
100         int l=strlen(s);
101         int j=0;// 当前节点的编号
102         for(int i=0;i<l;i++)
103         {
104             int c=idx(s[i]);
105             while(j&&!ch[j][c])
106             j=f[j];// 顺着失配边走
107             j=ch[j][c]; // 取到儿子
108             if(val[j])
109             ok(j);// 找到一个单词
110             else if(last[j])
111             ok(last[j]);// 当前节点不行就看看上一个单词出现的位置行不行
112         }
113     }
114 }ac;
115 int main()
116 {
117         scanf("%d",&n);
118         ac.Init();
119         for(int i=1;i<=n;i++)
120         {
121             scanf("%s",s);
122             ac.Insert(s,i);
123         }
124         ac.getfail();
125         scanf("%s",text);
126         ac.find(text);
127         printf("%d\n",ans);
128     return 0;
129 }
时间: 2024-10-05 22:58:55

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

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

模板,详见代码: #include<bits/stdc++.h> using namespace std; const int mxn=1e7+5; char str[mxn],p[80]; queue<int > q; namespace Trie { int tot,fail[mxn],val[mxn]; int t[mxn][26]; void ins(char *s) { int len=strlen(s),u=0; for(int i=0;i<len;++i) {

[模板]洛谷T3808 AC自动机(简单版)

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<ctime> 6 #include<cstdlib> 7 8 #include<string> 9 #include<stack> 10 #include<queue> 11 #include<vector> 1

[算法模版]AC自动机

[算法模版]AC自动机 基础内容 板子不再赘述,OI-WIKI有详细讲解. \(query\)函数则是遍历文本串的所有位置,在文本串的每个位置都沿着\(fail\)跳到根,将沿途所有元素答案++.意义在于累计所有以当前字符为结尾的所有模式串的答案.看代码就能很容易的理解. 另外\(e[i]\)记录的是第\(t\)个模式串结尾是哪个节点(所有节点均有唯一的编号). 贴个P5357 [模板]AC自动机(二次加强版)板子: #include<iostream> #include<cstdio&

AC自动机例题

P3808 [模板]AC自动机(简单版) [题目描述] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. #include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF=1e9+7; inline LL read(){ register LL x=0,f=1;register char c=getchar(); while(c<48||c>57){if(c=='-')f=

AC自动机 P3808 P3796

第一次写AC自动机 简单版的这道题可以在进行匹配的时候剪一下枝,应为之前比配过了,不用在匹配了. #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <queue> using namespace std; const int MAXN=1e6+10; queue<int> que; struct AC{ int

BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)

3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 1890  Solved: 877 [Submit][Status][Discuss] Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. Input 第一个一个整数N,表示有多少个单词,接下来N行每行一个单词.每个单词由小写字母组成,N<=200,单词长度不超过10^6

从Trie谈到AC自动机

ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字母,因此得名`字母树`. 出一张图让大家感受下. (image powered by SaiBu NaoCu) 上面那是一棵插入了 ape,app,applicant,application,bake,ban,banana 等词的Trie.红色结点表示接受态. 显然,查找时只需顺着链照下来,插入只需

[C#] 逆袭——自制日刷千题的AC自动机攻克HDU OJ

前言 做过杭电.浙大或是北大等ACM题库的人一定对“刷题”不陌生,以杭电OJ为例:首先打开首页(http://acm.hdu.edu.cn/),然后登陆,接着找到“Online Exercise”下的“Problem Archive”,然后从众多题目中选择一个进行读题.构思.编程.然后提交.最后查看题解状态,如果AC了表示这一题被攻克了,否则就要重做了~一般情况下,“刷题”要求精神高度集中且经验丰富,否则很难成功AC,有时候甚至做一题要浪费半天的时间!(有时网速卡了,比抢火车票还要急!) 楼主在

luogu P3808 【模板】AC自动机(简单版)

二次联通门 : luogu P3808 [模板]AC自动机(简单版) /* luogu P3808 [模板]AC自动机(简单版) 手速越来越快了 10分钟一个AC自动机 一遍过编译 + 一边AC 感觉不错 我也就做做板子题了.. */ #include <iostream> #include <cstring> #include <cstdio> #include <queue> #define Max 1000009 void read (int &