P3808 AC自动机(简单版)

P3808 AC自动机(简单版)

题目描述

给定 n 个模式串 si 和一个文本串 t,求有多少个不同的模式串在文本串里出现过。
两个模式串不同当且仅当他们编号不同。

输入格式

第一行是一个整数,表示模式串的个数 n
2 到第 (n+1) 行,每行一个字符串,第 (i+1) 行的字符串表示编号为 i 的模式串 si
最后一行是一个字符串,表示文本串 t

输出格式

输出一行一个整数表示答案。

------------------------------------------------------------------------------------

rt,我们需要维护一个AC自动机。
首先我们需要对所以模式串建立一颗Trie,然后将这个文本串放入这颗Trie中匹配

剩下的细节先咕着,因为上课了

code:

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int cnt,tot,n,ans;
char c[N],s[N];
struct Tree{
int son[26],id,fail,num;
}t[N];
void init()
{
for(int i=1;i<=cnt;i++)t[i]=Tree{{0},0,1,0};
cnt=1,ans=0;
}
void add(char c[])//常规Trie插入
{
int x=1,len=strlen(c);
for(int i=0;i<=len-1;i++)
{
int to=c[i]-'a';
if(t[x].son[to])
{
t[x].son[to];
}
else
{
t[x].son[to]=++cnt;
}
x=t[x].son[to];
}
t[x].num++;
return ;
}
void getfail()
{
queue<int> q;
for(int i=0;i<=25;i++)
{
int to=t[1].son[i];
if(!to)continue;
q.push(to);
t[to].fail=1;
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<26;i++)
{
int to=t[u].son[i];
if(to)
{
t[to].fail=t[t[u].fail].son[i];//fail:指向to的后缀(即[root->fail]这条路径上的字符串是[toot->to]的一个后缀)
//显然,fail在Trie上的深度要比to浅(前缀的长度肯定小于等于原串)
q.push(to);
}
else
{
t[u].son[i]=t[t[u].fail].son[i];//如果这个点没有字符,为了方便查询,将这个点连到后缀的儿子上方便匹配
}
}
}
return ;
}
void query(char s[])
{
int len=strlen(s);
int x=1;
for(int i=0;i<=len-1;i++)
{
int ch=s[i]-'a';
x=t[x].son[ch];
for(int j=x;1^j && ~t[j].num;j=t[j].fail)//查询,遍历树上所有的ch的fail指针,匹配对应字符串
{
ans+=t[j].num;
t[j].num=-1;
}
}
}
int main()
{
//freopen("ac.in","r",stdin);
//freopen("ac.out","w",stdout);
cin>>n;
init();
for(int i=1;i<=n;i++)
{
scanf("%s",c);
add(c);
}
getfail();
scanf("%s",s);
query(s);
printf("%d\n",ans);
return 0;
}
posted @   liuboom  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示