bzoj3172[Tjoi2013]单词

bzoj3172[Tjoi2013]单词

题意:

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。注意论文中单词之间是有分隔的。单词数≤200,长度≤1000000

题解:

先将每个单词插入trie,经过的节点的sum[i]++,然后求fail函数,求完后按BFS序倒过来维护sum[fail[i]]+=sum[i],最后输出第i个单词末尾字符节点的sum值。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 1000010
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7 
 8 int ch[maxn][26],sum[maxn],pos[maxn],q[maxn],n,tot,fail[maxn]; char s[maxn];
 9 int insert(char *s){
10     int l=strlen(s+1),x=0;
11     inc(i,1,l){if(!ch[x][s[i]-'a'])ch[x][s[i]-'a']=++tot; x=ch[x][s[i]-'a']; sum[x]++;} return x;
12 }
13 void getfail(){
14     int l=1,r=0; inc(i,0,25)if(ch[0][i])q[++r]=ch[0][i],fail[ch[0][i]]=0;
15     while(l<=r){
16         int x=q[l++];
17         inc(i,0,25)if(ch[x][i]){
18             int y=fail[x]; while(y&&!ch[y][i])y=fail[y];
19             if(ch[y][i])fail[ch[x][i]]=ch[y][i]; q[++r]=ch[x][i];
20         }
21     }
22     for(int i=r;i;i--)sum[fail[q[i]]]+=sum[q[i]];
23 }
24 int main(){
25     scanf("%d",&n); tot=0; inc(i,1,n){scanf("%s",s+1); pos[i]=insert(s);}
26     getfail(); inc(i,1,n)printf("%d\n",sum[pos[i]]);
27 }

 

20160620

posted @ 2016-07-24 16:31  YuanZiming  阅读(461)  评论(0编辑  收藏  举报