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