国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

bzoj3172: [Tjoi2013]單詞

2019-11-08 19:50:44
字體:
來源:轉載
供稿:網友

bzoj3172: [Tjoi2013]單詞

Description

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

Input

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

Output

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

Sample Input

3

a

aa

aaa

Sample Output

6

3

1

題目大意

給出n個單詞,求每個單詞在這n個單詞中各出現了多少次。

題解

不難想到將這n個單詞建立一個AC自動機,并在每個節點維護一個sum值,然后將每個單詞的每個節點沿著fail指針走一遍,路徑上所有sum++。但是這樣做會TLE。 考慮到將fail指針反向的話是一棵樹,而每個單詞的出現次數就是它的單詞結尾節點所在的子樹中的sum總和。所以先在插入每個單詞的時候將路徑上所有節點的sum++,然后按照bfs序的反序(即隊列從隊尾到隊首),將每個節點的fail值累加到他的父親節點(fail指針指向的節點),最后直接輸出答案即可。

#include<cstdio>#include<iostream>#include<cstring>#include<queue>using namespace std;const int max_size = 1000000 + 10, ch_size = 26;char s[max_size];int n;struct Trie{ int ch[max_size][ch_size]; int f[max_size], sum[max_size], fin[210]; int q[max_size]; int idx['z'+1]; int sz; Trie() {sz = 1; for(char i = 'a'; i <= 'z'; i++) idx[i] = i-'a';} void insert(char *s, int k){ int u = 0, len = strlen(s); for(int i = 0; i < len; i++){ int x = idx[s[i]]; if(!ch[u][x]) ch[u][x] = sz++; u = ch[u][x]; sum[u]++; } fin[k] = u; } void get_fail(){ int lt = 1, rt = 0; for(int i = 0; i < ch_size; i++){ int u = ch[0][i]; if(u){ f[u] = 0; q[++rt] = u; } } while(lt <= rt){ int r = q[lt]; lt++; for(int i = 0; i < ch_size; i++){ int &u = ch[r][i]; if(!u) continue; int v = f[r]; while(v && !ch[v][i]) v = f[v]; f[u] = ch[v][i]; q[++rt] = u; } } for(; rt; rt--) sum[f[q[rt]]] += sum[q[rt]]; }}ac;void init(){ scanf("%d", &n); for(int i = 1; i <= n; i++){ scanf("%s", s); ac.insert(s, i); }}void work(){ ac.get_fail(); for(int i = 1; i <= n; i++)
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宝丰县| 娄烦县| 龙泉市| 桂阳县| 多伦县| 文登市| 牡丹江市| 武宁县| 特克斯县| 栾川县| 信阳市| 佛冈县| 怀安县| 轮台县| 黄陵县| 上林县| 句容市| 台安县| 德阳市| 凤阳县| 镇沅| 西充县| 吴旗县| 闻喜县| 佛冈县| 靖远县| 东山县| 西畴县| 任丘市| 闽侯县| 绥宁县| 乐昌市| 泸西县| 唐河县| 宜黄县| 台中市| 卫辉市| 横峰县| 分宜县| 大化| 德钦县|