[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;

}

 

你可能感兴趣的:(单词)