[TJOI2013]单词

可以用后缀数组来做。

我说以下ac自动机的做法:

加入每个单词,对路径上的所有点累计访问次数。

构建fail指针。

把每个节点的访问次数累加到它的fail上。具体有代码。。(我写的很挫 - -)

/**
 * Problem:Word
 * Author:Shun Yao
 * Time:2013.5.21
 * Result:Accepted
 * Memo:AC-automation
 */

#include <cstring>
#include <cstdlib>
#include <cstdio>

using namespace std;

long n, l, r;
char s[201][1000000];

class node {
public:
	long v;
	node *next[27], *fail;
	node() {
		v = 0;
	}
	~node() {}
} *root, *p, *q[1000000];

int main() {
	static long i;
	static char *ss;
	freopen("word.in", "r", stdin);
	freopen("word.out", "w", stdout);
	scanf("%ld", &n);
	root = new node();
	for (i = 1; i <= n; ++i) {
		scanf(" %s", s[i]);
		p = root;
		ss = s[i];
		while (*ss) {
			if (!p->next[*ss - 'a'])
				p->next[*ss - 'a'] = new node();
			p = p->next[*ss - 'a'];
			++p->v;
			++ss;
		}
	}
	l = 0;
	r = 0;
	for (i = 0; i < 26; ++i)
		if (root->next[i]) {
			q[r++] = root->next[i];
			root->next[i]->fail = root;
		}
	while (l < r) {
		for (i = 0; i < 26; ++i)
			if (q[l]->next[i]) {
				q[r++] = q[l]->next[i];
				p = q[l]->fail;
				while (p != root && !p->next[i])
					p = p->fail;
				if (p->next[i])
					q[l]->next[i]->fail = p->next[i];
				else
					q[l]->next[i]->fail = root;
			}
		++l;
	}
	for (i = r - 1; i >= 0; --i)
		q[i]->fail->v += q[i]->v;
	for (i = 1; i <= n; ++i) {
		p = root;
		ss = s[i];
		while (*ss) {
			if (!p->next[*ss - 'a'])
				p->next[*ss - 'a'] = new node();
			p = p->next[*ss - 'a'];
			++ss;
		}
		printf("%ld\n", p->v);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

 

posted @ 2013-05-21 21:27  hsuppr  阅读(319)  评论(0编辑  收藏  举报