[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; }
作者:HSUPPR
出处:http://www.cnblogs.com/hsuppr/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出
原文链接,否则保留追究法律责任的权利。