题目背景
通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。
这是一道简单的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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
char s[maxn];
namespace ac
{
int tot, ext[maxn], fail[maxn], trie[maxn][26];
queue<int> q;
void insert(char* s)
{
int u = 0;
for (int i = 1; s[i]; i++)
{
int c = s[i] - 'a';
if (!trie[u][c]) trie[u][c] = ++tot;
u = trie[u][c];
}
ext[u]++;
}
void build()
{
for (int i = 0; i < 26; i++) if (trie[0][i]) q.push(trie[0][i]);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0; i < 26; i++)
{
if (trie[u][i])
{
fail[trie[u][i]] = trie[fail[u]][i];
q.push(trie[u][i]);
}
else trie[u][i] = trie[fail[u]][i];
}
}
}
int query(char* t)
{
int u = 0, res = 0;
for (int i = 1; t[i]; i++)
{
u = trie[u][t[i] - 'a'];
for (int j = u; j && ~ext[j]; j = fail[j])
{
res += ext[j];
ext[j] = -1;
}
}
return res;
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else freopen("input.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
while (n--)
{
scanf("%s", s + 1);
ac::insert(s);
}
scanf("%s", s + 1);
ac::build();
printf("%d\n", ac::query(s));
return 0;
}