bzoj 3172 [Tjoi2013]单词(fail树,DP)

 

3172: [Tjoi2013]单词

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2327  Solved: 1093
[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

 

【题意】

 

       题目的意思是这样的,给若干个单词,求每个单词在这一堆单词中的出现次数。 出题人语文水平高

      

【思路】

      

  AC自动机. fail树

  AC自动机中的fail指针指向该串的一个后缀,将fail指针反向后得到一棵fail树,利用getFail后的bfs序在树上进行DP统计出现次数。

 

【代码】

 

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

 

你可能感兴趣的:(bzoj 3172 [Tjoi2013]单词(fail树,DP))