P5357 【模板】AC 自动机
题目背景
本题原为“AC 自动机(二次加强版)”。完成本题前可以先完成 AC 自动机(简单版) 和 AC 自动机(简单版 II) 两道题,为 AC 自动机更简单的应用。
题目描述
给你一个文本串 \(S\) 和 \(n\) 个模式串 \(T_{1 \sim n}\),请你分别求出每个模式串 \(T_i\) 在 \(S\) 中出现的次数。
输入格式
第一行包含一个正整数 \(n\) 表示模式串的个数。
接下来 \(n\) 行,第 \(i\) 行包含一个由小写英文字母构成的非空字符串 \(T_i\)。
最后一行包含一个由小写英文字母构成的非空字符串 \(S\)。
数据不保证任意两个模式串不相同。
输出格式
输出包含 \(n\) 行,其中第 \(i\) 行包含一个非负整数表示 \(T_i\) 在 \(S\) 中出现的次数。
输入输出样例 #1
输入 #1
5
a
bb
aa
abaa
abaaa
abaaabaa
输出 #1
6
0
3
2
1
说明/提示
对于 \(100 \%\) 的数据,\(1 \le n \le 2 \times {10}^5\),\(T_{1 \sim n}\) 的长度总和不超过 \(2 \times {10}^5\),\(S\) 的长度不超过 \(2 \times {10}^6\)。
把这个数据加强版的代码稍加修改即可通过另外两题了
题解
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
int n;
int tree[N][26];
int fail[N];
int cnt = 0;
int ed[N];
int t[N];
vector<int>e[N];
void insert(int idx,string s)
{
int u = 0;
for(auto ch:s)
{
int c = ch - 'a';
if(tree[u][c]==0)tree[u][c] = ++cnt;
u = tree[u][c];
}
ed[idx] = u;
}
void setfail()
{
queue<int>q;
for(int c =0;c<26;++c)
{
if(tree[0][c])q.push(tree[0][c]);
}
while(!q.empty())
{
int u = q.front();q.pop();
for(int c=0;c<26;c++)
{
if(tree[u][c]==0)
{
tree[u][c] = tree[fail[u]][c];
}
else
{
fail[tree[u][c]] = tree[fail[u]][c];
q.push(tree[u][c]);
}
}
}
}
void f1(int u)
{
for(int v:e[u])
{
f1(v);
t[u]+=t[v];
}
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
insert(i,s);
}
setfail();
string text;
cin>>text;
int u = 0;
for(auto ch:text)
{
int c = ch-'a';
u = tree[u][c];
t[u]++;
}
for(int i=1;i<=cnt;i++)
{
e[fail[i]].push_back(i);
}
f1(0);
for(int i=1;i<=n;i++)
{
cout<<t[ed[i]]<<endl;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int _=1;
// cin>>_;
while(_--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号