bzoj 3172 [Tjoi2013]单词(fail树,DP)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3172 [Tjoi2013]单词(fail树,DP)相关的知识,希望对你有一定的参考价值。
3172: [Tjoi2013]单词
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2327 Solved: 1093
[Submit][Status][Discuss]
Description
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
Input
第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6
Output
输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。
Sample Input
3
a
aa
aaa
a
aa
aaa
Sample Output
6
3
1
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)的主要内容,如果未能解决你的问题,请参考以下文章