【BZOJ3172】[TJOI2013]单词

【BZOJ3172】[TJOI2013]单词

题面

bzoj

luogu

题解

我们考虑一下$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; 
} 

 

posted @ 2019-01-09 11:45  heyujun  阅读(189)  评论(2编辑  收藏  举报