BZOJ_3172_[TJOI2013]_单词_(AC自动机)

描述


http://www.lydsy.com/JudgeOnline/problem.php?id=3172

\(n\)个单词组成一篇文章,求每个单词在文章中出现的次数.

 

分析


这道题很像BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

一个单词出现过,那么一定是某个单词的某个前缀的后缀,可以通过这个前缀的末尾沿着失配边找到它.我们要统计有多少点可以这样找到它.

建立fail树,很显然,单词\(x\)子树中的所有点都可以沿着失配边找到\(x\),这样我们只用记录每个点有多少次就行了.

(eg:如果文章是 a aa aaa,那么a有3次(三个单词各一次),aa有2次(第二个单词和第三个单词),aaa有1次(第三个单词)).

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e6+10,type=26;
 4 int n,m;
 5 char s[maxn];
 6 struct Aho_Corasick{
 7     int sz;
 8     int q[maxn],val[maxn],pos[maxn],f[maxn];
 9     int ch[maxn][type];
10     Aho_Corasick():sz(0){memset(ch[0],0,sizeof ch[0]);memset(val,0,sizeof val);}
11     inline int insert(char *s){
12         int u=0,m=strlen(s+1);
13         for(int i=1;i<=m;i++){
14             int c=s[i]-'a';
15             if(!ch[u][c]){
16                 memset(ch[++sz],0,sizeof ch[sz]); val[sz]=0;
17                 ch[u][c]=sz;
18             }
19             u=ch[u][c];
20             val[u]++;
21         }
22         return u;
23     }
24     inline void get_fail(){
25         int L=1,R=0;
26         for(int c=0;c<type;c++){
27             int u=ch[0][c];
28             if(u){f[u]=0;q[++R]=u;}
29         }
30         while(L<=R){
31             int u=q[L++];
32             for(int c=0;c<type;c++){
33                 int t=ch[u][c];
34                 if(!t){ch[u][c]=ch[f[u]][c];continue;}
35                 int v=f[u];
36                 f[t]=ch[v][c];
37                 q[++R]=t;
38             }
39         }
40         for(int i=sz;i;i--) val[f[q[i]]]+=val[q[i]];
41     }
42     inline void solve(){
43         for(int i=1;i<=n;i++) printf("%d\n",val[pos[i]]);
44     }
45 }ac;
46 inline void solve(){
47     ac.get_fail();
48     ac.solve();
49 }
50 inline void init(){
51     scanf("%d",&n);
52     for(int i=1;i<=n;i++){
53         scanf("%s",s+1);
54         ac.pos[i]=ac.insert(s);
55     }
56 }
57 int main(){
58     init();
59     solve();
60     return 0;
61 }
View Code

 

3172: [Tjoi2013]单词

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2837  Solved: 1356
[Submit][Status][Discuss]

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

HINT

Source

 

posted @ 2016-07-06 18:14  晴歌。  阅读(115)  评论(0编辑  收藏  举报