【BZOJ3172】 [Tjoi2013]单词

【题意】

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

 

【分析】

      个人觉得是用了反fail树的思想,Ans[i]=t[i].cnt+∑Ans[反fail]...不过因为有些节点的反fail会有很多个,存起来不方便。但是AC自动机的fail却只有一个,而且我们在建立AC自动机的时候是用类似宽搜的方法建的,所以保存在队列里的节点肯定是由深到浅。然后我们就可以从后往前for一遍,把i的cnt加入到i的fail的cnt里,最后每个单词最末节点的cnt就是答案。

 

代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 
 5 const int Maxn=(int)1e4;
 6 const int Maxl=200;
 7 
 8 struct node
 9 {
10     int son[27],fail,cnt,ans;
11 }t[16035707];
12 
13 int n,m,cnt=0;
14 int q[Maxn*Maxl+10],bj[Maxn];
15 char s[Maxl];
16 
17 void floy()
18 {
19     int i;
20     for(i=1;i<=Maxn;i++) t[i].fail=0,t[i].ans=0;
21 }
22 
23 void read() 
24 {
25      memset(bj,0,sizeof(bj));
26      int i,j,x,ind;
27      scanf("%d",&n);
28      getchar();
29      for(i=1;i<=n;i++)
30      {
31          scanf("%s",s+1);
32          m=strlen(s+1);
33          x=0;
34          for(j=1;j<=m;j++)
35          {
36              ind=s[j]-'a'+1;
37              if(!t[x].son[ind]) t[x].son[ind]=++cnt;
38              x=t[x].son[ind];
39              t[x].cnt++;
40              if(j==m) bj[i]=cnt;
41          }
42      }
43 }
44 
45 void Build_AC()
46 {
47     int i,x,y,j;
48     q[0]=0;
49     q[++q[0]]=0;
50     //for(i=1;i<=26;i++)  if(t[0].son[i]) q[++q[0]]=t[0].son[i]; 
51     for(i=1;i<=q[0];i++)
52     {
53         x=q[i];
54         y=t[x].fail;
55         for(j=1;j<=26;j++)
56             if(t[x].son[j])   
57             {                
58                 //t[t[x].son[j]].fail=t[y].son[j];
59                 t[t[x].son[j]].fail=x?t[y].son[j]:x; 
60                 q[++q[0]]=t[x].son[j];   
61             }
62             else t[x].son[j]=t[y].son[j];
63     }
64     for(i=q[0];i>=1;i--)
65     {
66         t[t[q[i]].fail].cnt+=t[q[i]].cnt;
67     }
68 }
69 
70 int main()
71 {
72     read();
73     Build_AC();
74     for(int i=1;i<=n;i++) printf("%d\n",t[bj[i]].cnt);
75 }
[BZOJ3172]

 

2016-07-12 10:12:39

posted @ 2016-07-12 10:09  konjak魔芋  阅读(338)  评论(0编辑  收藏  举报