题目背景
通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。
这是一道简单的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;
代码如下
#include <iostream>
#include <queue>
#define maxn 1000005
#define MAX 26
using namespace std;
struct AC{
int e; //以这个节点为结尾的模式串有几个
int next[MAX];
int fail;
}tree[maxn];
const int root = 0;
int cnt = 0;
void build(string str) //建立字典树
{
int now = root;
for(int i = 0; i < str.size(); i ++){
if(!tree[now].next[str[i] - 'a'])
tree[now].next[str[i] - 'a'] = ++cnt;
now = tree[now].next[str[i] - 'a'];
if(i == str.size() - 1)
tree[now].e ++;
}
}
void get_fail() //将trie树补全成trie图
{
queue<int> que;
for(int i = 0; i < MAX; i ++){
if(tree[0].next[i]){
tree[tree[0].next[i]].fail = 0;
que.push(tree[0].next[i]);
}
}
while(!que.empty()){
int now = que.front();
que.pop();
for(int i = 0; i < MAX; i ++){
if(tree[now].next[i]){
tree[tree[now].next[i]].fail = tree[tree[now].fail].next[i];
que.push(tree[now].next[i]);
}
else
tree[now].next[i] = tree[tree[now].fail].next[i];
}
}
}
int ac_query(string str) //匹配
{
int now = root;
int ans = 0;
for(int i = 0; i < str.size(); i ++){
now = tree[now].next[str[i] - 'a'];
int u = now;
while(u && tree[u].e != -1){
ans += tree[u].e;
tree[u].e = -1;
u = tree[u].fail;
}
}
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
int n;
cin >> n;
for(int i = 0; i < n; i ++){
string str;
cin >> str;
build(str);
}
get_fail();
string s;
cin >> s;
cout << ac_query(s) << endl;
return 0;
}