【BZOJ3172】[TJOI2013]单词
【BZOJ3172】[TJOI2013]单词
题面
题解
我们考虑一下$AC$自动机的匹配过程
发现每个字符串的出现次数就是$fail$树上串最后字符节点的权值之和
然后就比较简单了
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int MAX_N = 1e6 + 5;
int c[MAX_N][26], size[MAX_N], End[MAX_N], fail[MAX_N], tot;
int q[MAX_N], cnt;
void insert(char *s, int id) {
int o = 0;
for (int l = strlen(s), i = 0; i < l; i++) {
int son = s[i] - 'a';
if (!c[o][son]) c[o][son] = ++tot;
o = c[o][son]; ++size[o];
}
End[id] = o;
}
void build() {
static queue<int> que;
q[++cnt] = 0;
for (int i = 0; i < 26; i++) if (c[0][i]) que.push(c[0][i]), fail[c[0][i]] = 0, q[++cnt] = c[0][i];
while (!que.empty()) {
int o = que.front(); que.pop();
for (int i = 0; i < 26; i++)
if (c[o][i]) fail[c[o][i]] = c[fail[o]][i], que.push(c[o][i]), q[++cnt] = c[o][i];
else c[o][i] = c[fail[o]][i];
}
}
int N; char s[MAX_N];
int main () {
scanf("%d", &N);
for (int i = 1; i <= N; i++) scanf("%s", s), insert(s, i);
build();
for (int i = cnt; i; i--) size[fail[q[i]]] += size[q[i]];
for (int i = 1; i <= N; i++) printf("%d\n", size[End[i]]);
return 0;
}