【BZOJ 3172】 [Tjoi2013]单词

Description

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

Input

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

Output

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

Sample Input

3
a
aa
aaa

Sample Output

6
3
1
 
fail树的DP
AC自动机的性质,fail指针指向的地方保证前缀相同,所以倒着跑DP就好了
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define ll long long 
 7 #define inf 1000000000
 8 #define mod 1000000007
 9 const int N=1000005;
10 struct acm{
11     int cnt;
12     int next[1000005][26],sum[1000005],fail[1000005],q[1000005];
13     char ch[1000005];
14     acm(){
15         cnt=1;
16         for (int i=0;i<26;i++) next[0][i]=1;
17     }
18     void ins(int &pos){
19         int now=1;
20         scanf("%s",ch);
21         int n=strlen(ch);
22         for (int i=0;i<n;i++){
23             if(!next[now][ch[i]-'a']) 
24             next[now][ch[i]-'a']=++cnt;
25             now=next[now][ch[i]-'a'];
26             sum[now]++; 
27         }
28         pos=now;
29     }
30     void buildfail(){
31         int head=0,tail=1;
32         q[0]=1,fail[1]=0;
33         while(head!=tail){
34             int now=q[head];head++;
35             for(int i=0;i<26;i++){
36                 int v=next[now][i];
37                 if(!v) continue;
38                 int k=fail[now];
39                 while(!next[k][i]) k=fail[k];
40                 fail[v]=next[k][i];
41                 q[tail++]=v;
42             } 
43         }
44          for(int i=tail-1;i>=0;i--) 
45             sum[fail[q[i]]]+=sum[q[i]];//就是这里啦!!!
46     }
47 }acm;
48 int n,pos[N];
49 int main(){
50     scanf("%d",&n);
51     for(int i=1;i<=n;i++) acm.ins(pos[i]);
52     acm.buildfail();
53     for (int i=1;i<=n;i++) printf("%d\n",acm.sum[pos[i]]);
54 }

 

posted @ 2016-02-20 07:43  Alisahhh  阅读(171)  评论(0编辑  收藏  举报