UVa Live 4670 Dominating Patterns - Aho-Corasick自动机

题目传送门

  快速的通道I

  快速的通道II

题目大意

  给定一堆短串,和一个文本串,问哪些短串在文本串中出现的次数最多。

  我觉得刘汝佳的做法,时间复杂度有问题。只是似乎这道题短串串长太短不好卡。比如给出的串是一坨$a$。暴力跳$last$会比较gg。

  考虑如何计算一个短串在长串中的出现次数。

  当短串在长串的某个位置出现的时候,这意味着它的结束位置在fail树上的祖先中某个状态是短串的终止状态。

  我们会在长串经过的每个状态都去做这样一个操作来统计每个短串出现的次数。

  这个可以看成在fail树上的以根为端点的链上修改操作。

  由于询问可以看成是离线的,所以每次可以单点修改cnt,最后做一次前缀和。

Code

  1 /**
  2  * UVa Live
  3  * Problem#4670
  4  * Accepted
  5  * Time: 45ms
  6  */
  7 #include <iostream>
  8 #include <cstring>
  9 #include <cstdio>
 10 #include <queue>
 11 using namespace std;
 12 typedef bool boolean;
 13 
 14 const int MaxNode = 10505, N = 152, L = 75;
 15 
 16 typedef class TrieNode {
 17     public:
 18         int cnt;
 19         TrieNode* ch[26];
 20         TrieNode* fail;
 21 }TrieNode;
 22 
 23 TrieNode pool[MaxNode];
 24 TrieNode *top;
 25 
 26 TrieNode* newnode() {
 27     top->cnt = 0;
 28     memset(top->ch, 0, sizeof(top->ch));
 29     top->fail = NULL;
 30     return top++;
 31 }
 32 
 33 typedef class AhoCorasick {
 34     public:
 35         TrieNode* rt;
 36 
 37         AhoCorasick() {
 38             top = pool;
 39             rt = newnode();
 40         }
 41 
 42         TrieNode* insert(char* str) {
 43             TrieNode* p = rt;
 44             for (int i = 0, c; str[i]; i++) {
 45                 c = str[i] - 'a';
 46                 if (!p->ch[c])
 47                     p->ch[c] = newnode();
 48                 p = p->ch[c];
 49             }
 50             return p;
 51         }
 52 
 53         void build() {
 54             queue<TrieNode*> que;
 55             rt->fail = NULL;
 56             que.push(rt);
 57             while (!que.empty()) {
 58                 TrieNode* p = que.front();
 59                 que.pop();
 60                 for (int i = 0; i < 26; i++) {
 61                     TrieNode *np = p->ch[i];
 62                     if (!np)    continue;
 63                     que.push(np);
 64                     TrieNode* f = p->fail;
 65                     while (f && !f->ch[i])    f = f->fail;
 66                     if (!f)
 67                         np->fail = rt;
 68                     else
 69                         np->fail = f->ch[i];
 70                 }
 71             }
 72         }
 73 
 74         void query(char *str) {
 75             TrieNode *p = rt;
 76             for (int i = 0; str[i]; i++) {
 77                 int c = str[i] - 'a';
 78                 while (p && !p->ch[c])    p = p->fail;
 79                 if (!p)
 80                     p = rt;
 81                 else
 82                     p = p->ch[c];
 83                 p->cnt++;    
 84             }
 85             for (p = top - 1; p != pool; p--)
 86                 p->fail->cnt += p->cnt;
 87         }
 88 }AhoCorasick;
 89 
 90 int n;
 91 AhoCorasick ac;
 92 char S[1000005];
 93 char T[N][L];
 94 TrieNode* ps[N];
 95 
 96 inline boolean init() {
 97     scanf("%d", &n);
 98     if (!n)    return false;
 99     ac = AhoCorasick();
100     for (int i = 1; i <= n; i++) {
101         scanf("%s", T[i]);
102         ps[i] = ac.insert(T[i]);
103     }
104     scanf("%s", S);
105     return true;
106 }
107 
108 inline void solve() {
109     ac.build();
110     ac.query(S);
111     int maxt = 0;
112     for (int i = 1; i <= n; i++)
113         if (ps[i]->cnt > maxt)
114             maxt = ps[i]->cnt;
115     printf("%d\n", maxt);
116     for (int i = 1; i <= n; i++)
117         if (ps[i]->cnt == maxt)
118             puts(T[i]);
119 }
120 
121 int main() {
122     while(init())
123         solve();
124     return 0;
125 }
posted @ 2018-03-24 19:10  阿波罗2003  阅读(179)  评论(0编辑  收藏  举报