题目背景
这是一道简单的AC自动机模板题。
用于检测正确性以及算法常数。
为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。
管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意
题目描述
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入输出格式
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案
输入输出样例
输入样例#1:
2
a
aa
aa
输出样例#1:
2
分析:一道ac自动机的裸题。不过每个模式串只算一次。今天被字符串题虐得好惨呀,只能回来填坑了。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
const int maxn=1e6+7;
using namespace std;
char s[maxn];
int n,cnt;
struct node{
int fail,end;
int vis[26];
}t[maxn];
void build(char s[maxn])
{
int len=strlen(s);
int now=0;
for (int i=0;i<len;i++)
{
if (!t[now].vis[s[i]-'a']) t[now].vis[s[i]-'a']=++cnt;
now=t[now].vis[s[i]-'a'];
}
t[now].end++;
}
void getfail()
{
queue <int> q;
for (int i=0;i<26;i++)
{
if (t[0].vis[i])
{
t[t[0].vis[i]].fail=0;
q.push(t[0].vis[i]);
}
}
while (!q.empty())
{
int u=q.front();
q.pop();
for (int i=0;i<26;i++)
if (t[u].vis[i])
{
t[t[u].vis[i]].fail=t[t[u].fail].vis[i];
q.push(t[u].vis[i]);
}
else
{
t[u].vis[i]=t[t[u].fail].vis[i];
}
}
}
int find(char s[maxn])
{
int ans=0;
int now=0;
int len=strlen(s);
for (int i=0;i<len;i++)
{
now=t[now].vis[s[i]-'a'];
for (int k=now;k&&(t[k].end!=-1);k=t[k].fail)
{
ans+=t[k].end;
t[k].end=-1;
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
build(s);
}
getfail();
scanf("%s",s);
printf("%d",find(s));
}