我觉得刘汝佳的做法,时间复杂度有问题。只是似乎这道题短串串长太短不好卡。比如给出的串是一坨$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 }