题目:
小张最近在忙毕设,所以一直在读论文。一篇论文是由许多单词组成的。
但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。
输入
第一行一个整数N,表示有N个单词。接下来N行每行一个单词,每个单词都由小写字母('a'-'z')组成。(N≤200, 单词总长度不超过106)
输出
输出N个整数,第i行的数表示第i个单词在文章中出现了多少次。
样例输入
3
a
aa
aaa
样例输出
6
3
1
提示
可以将论文内容看做'a aa aaa'。
题解:可以用AC自动机来解,插入单词的时候,在每个字母位置计数器加1,统计每个单词结尾的计数器即可。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 250 #define maxn 1000100 struct TNode { TNode *fail; TNode *next[26]; int cnt; TNode() { cnt = 0; for(int i = 0; i < 26; i++) next[i] = NULL; fail = NULL; return; } }; TNode *root; int Tcnt; TNode *TQ[N]; void Insert(const char *s) { int len = strlen(s); TNode *p = root; for(int i = 0; i < len; i++) { if(p->next[s[i]-'a'] == NULL) p->next[s[i]-'a'] = new TNode(); p = p->next[s[i]-'a']; p->cnt++; } TQ[Tcnt++] = p; return ; } TNode *queue[maxn]; void build_ac_automation() { int front, rear; front = rear = 0; root -> fail = root; for(int i = 0; i < 26; i++) { if(root->next[i] != NULL) { root ->next[i]->fail = root; queue[rear++] = root->next[i]; } } while(front < rear) { TNode *p = queue[front++]; for(int i = 0; i < 26; i++) { TNode *q = p->fail; if(p->next[i] == NULL) continue; queue[rear++] = p->next[i]; while(q->next[i] == NULL && q!=root) q = q->fail; if(q->next[i] == NULL) p->next[i]->fail = root; else p->next[i]->fail = q->next[i]; } } while(rear>0){ --rear; queue[rear]->fail->cnt += queue[rear]->cnt; } return ; } char s[1000010]; int main() { int T,n; while(~scanf("%d", &n)) { Tcnt = 0; root = new TNode(); scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%s", s); Insert(s); } build_ac_automation(); for(int i = 0; i < n; i++) printf("%d ", TQ[i]->cnt); } return 0; }