初学ac自动机。
ac自动机相当于在trie上建立kmp中的ne指针(fail树)
建树的函数build()
比较固定;利用bfs+queue的特点还可以同时求出trie的拓扑序。
匹配的时候就可以灵活操作了。。
题意
某人读论文,一篇论文是由许多单词组成的。
但他发现一个单词会在论文中出现很多次,现在他想知道每个单词分别在论文中出现多少次。
输入格式
第一行一个整数 N,表示有多少个单词。
接下来 N 行每行一个单词,单词中只包含小写字母。
输出格式
输出 N 个整数,每个整数占一行,第 i 行的数字表示第 i 个单词在文章中出现了多少次。
数据范围
1≤N≤200,
所有单词长度的总和不超过 106。
输入样例:
3
a
aa
aaa
输出样例:
6
3
1
分析
先建立自动机,发现只需要统计每个单词能被多少个节点跳到就行了。
举例: s=“abcd”; t=“abcdeabcde”
在trie树上:
t[3]会指向s[3](也就是自己,s[3]在trie树上与t[3]是同一个位置,统计为cnt[s[3]]=2)
t[8]会指向s[3](在trie树上与t[3]是同一个位置)
所以,s[3]这个位置的cnt初值为2,又被一个节点指向了->ans=3。
解释的很抽象,,
于是:将所有单词建立trie图之后,利用顺便求出来的拓扑序自底向上更新每个节点的答案值就行了。
代码
#include <bits/stdc++.h>
using namespace std;
//-----pre_def----
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
#define rif(i, a, b) for (int i = (a); i >= (b); i--)
#define endl '\n'
#define init_h memset(h, -1, sizeof h), idx = 0;
#define lowbit(x) x &(-x)
//---------------
const int N = 1e6 + 10;
int n;
int tr[N][26], cnt[N], ne[N], idx;
char str[N];
int id[210];
int q[N];
void init()
{
memset(tr, 0, sizeof tr);
memset(cnt, 0, sizeof cnt);
memset(ne, 0, sizeof ne);
idx = 0;
}
void insert(int x)
{
int root = 0;
for (int i = 0; str[i]; i++)
{
int now = str[i] - 'a';
if (!tr[root][now])
tr[root][now] = ++idx;
root = tr[root][now];
cnt[root]++;
}
id[x] = root;
}
void ne_build()
{
int hh = 0, tt = -1;
fir(i, 0, 25) if (tr[0][i]) q[++tt] = tr[0][i];
while (hh <= tt)
{
auto t = q[hh++];
fir(i, 0, 25)
{
int now = tr[t][i];
if (now)
{
ne[now] = tr[ne[t]][i];
q[++tt] = now;
}
else
{
tr[t][i] = tr[ne[t]][i];
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int StartTime = clock();
#endif
scanf("%d", &n);
fir(i, 1, n)
{
scanf("%s", str);
insert(i);
}
ne_build(); //还可以顺便做topsort
rif(i, idx - 1, 0)//queue中一共存过idx个点,编号从0开始 所以是0~idx-1。
{
cnt[ne[q[i]]] += cnt[q[i]];
}
fir(i, 1, n) printf("%d\n", cnt[id[i]]);
#ifndef ONLINE_JUDGE
printf("Run_Time = %d ms\n", clock() - StartTime);
#endif
return 0;
}