P3808 【模版】AC自动机(简单版)
2017-07-06 17:45
211 查看
题目背景
这是一道简单的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=1000001; void read(int &n) { char c='+';int x=0;bool flag=0; while(c<'0'||c>'9'){c=getchar();if(c=='-')flag=1;} while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();} flag==1?n=-x:n=x; } char s[MAXN]; char text[MAXN]; int n; int ans=0; struct AC_Automata { int sz; int ch[MAXN][26];//trie树 int val[MAXN];// 记录是否有单词 int last[MAXN]; int f[MAXN]; int sigma_sz; void Init() { memset(ch[0],0,sizeof(ch[0])); sz=1; sigma_sz=26; } int idx(char c) { return c-'a'; } void Insert(char *s,int pos) { int l=strlen(s); int now=0; for(int i=0;i<l;i++) { int c=idx(s[i]); if(!ch[now][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[now][c]=sz++; } now=ch[now][c]; } val[now]++;//一个单词的结束 } void getfail() { f[0]=0; queue<int>q; for(int i=0;i<sigma_sz;i++) { int u=ch[0][i]; if(u)// 此处有单词出现 { f[u]=0;// 连向根节点 q.push(u); last[u]=0;// 上一个出现的单词一定是根节点 // 上面两条语句没什么卵用,只是为了帮助理解AC自动机的含义 } } while(!q.empty()) { int p=q.front();q.pop(); for(int i=0;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]=0; ok(last[pos]); } } void find(char *s)// 查找模式串 { int l=strlen(s); int j=0;// 当前节点的编号 for(int i=0;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=1;i<=n;i++) { scanf("%s",s); ac.Insert(s,i); } ac.getfail(); scanf("%s",text); ac.find(text); printf("%d\n",ans); return 0; }
相关文章推荐
- P3808 【模版】AC自动机(简单版)
- P3808 【模板】AC自动机(简单版)
- 【洛谷P3808】【模版】AC自动机(简单版)
- P3808 【模板】AC自动机(简单版)
- hdu 2896 病毒侵袭 (AC自动机模版)
- hdu2222 ac自动机模版
- hdu 3065 病毒侵袭持续中 AC自动机模版题
- AC自动机模版
- poj 1625 Censored! 【AC自动机 + DP + 强力大数模版】
- HDU 5384 AC自动机模版
- ac自动机模版hdu2222
- AC自动机模版
- luogu P3808 【模板】AC自动机(简单版)
- luogu P3808 【模板】AC自动机(简单版)
- HDU 2222 AC自动机模版题
- ac自动机模版(hdu 5384)
- HDU 2222 AC自动机模版题
- Luogu P3808 AC自动机简单版___AC自动机
- AC自动机模版
- ac自动机模版(hdu2222)