1. 程式人生 > >bzoj3172 [Tjoi2013]單詞

bzoj3172 [Tjoi2013]單詞

node ac自動機 con amp inline DC ace bzoj3 har

[Tjoi2013]單詞

Time Limit: 10 Sec Memory Limit: 512 MB

Description

某人讀論文,一篇論文是由許多單詞組成。但他發現一個單詞會在論文中出現很多次,現在想知道每個單詞分別在論文中出現多少次。

Input

第一個一個整數N,表示有多少個單詞,接下來N行每行一個單詞。每個單詞由小寫字母組成,N<=200,單詞長度不超過10^6

Output

輸出N個整數,第i行的數字表示第i個單詞在文章中出現了多少次。

Sample Input

3

a

aa

aaa

Sample Output

6

3

1














由KMP轉向AC自動機。。。。感覺還可以,自動腦補.jpg

大概就是你一個串走了次他的fail能連接的地方顯然也可以走,你倒著搞一波就差不多了。。。


#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
struct lpl{
    int sum, fail, ch[30];
}node[maxn];
int n, len, cnt, tot, pos[205], Q[maxn];
char s[maxn];

inline void putit()
{
    scanf("%d", &n);    int now, lin; cnt = 1
; for(int i = 1; i <= n; ++i){ scanf("%s", s + 1); len = strlen(s + 1); now = 1; for(int j = 1; j <= len; ++j){ lin = s[j] - 'a' + 1; if(!node[now].ch[lin]){node[now].ch[lin] = ++cnt;} now = node[now].ch[lin]; node[now].sum++; if
(j == len) pos[i] = now; } } } inline void workk() { queue<int> q; q.push(1); int now, t; while(!q.empty()){ now = q.front(); q.pop(); Q[++tot] = now; for(int i = 1; i <= 26; ++i){ if(!node[now].ch[i]) continue; q.push(node[now].ch[i]); if(now == 1){ node[node[now].ch[i]].fail = 1; continue; } t = node[now].fail; while(!node[t].ch[i] && t) t = node[t].fail; if(!t) node[node[now].ch[i]].fail = 1; else node[node[now].ch[i]].fail = node[t].ch[i]; } } } inline void print() { for(int i = tot; i >= 1; --i) node[node[Q[i]].fail].sum += node[Q[i]].sum; for(int i = 1; i <= n; ++i) printf("%d\n", node[pos[i]].sum); } int main() { putit(); workk(); print(); return 0; }

bzoj3172 [Tjoi2013]單詞