【BZOJ 3172】 [Tjoi2013]单词
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
fail树的DP
AC自动机的性质,fail指针指向的地方保证前缀相同,所以倒着跑DP就好了
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #define ll long long 7 #define inf 1000000000 8 #define mod 1000000007 9 const int N=1000005; 10 struct acm{ 11 int cnt; 12 int next[1000005][26],sum[1000005],fail[1000005],q[1000005]; 13 char ch[1000005]; 14 acm(){ 15 cnt=1; 16 for (int i=0;i<26;i++) next[0][i]=1; 17 } 18 void ins(int &pos){ 19 int now=1; 20 scanf("%s",ch); 21 int n=strlen(ch); 22 for (int i=0;i<n;i++){ 23 if(!next[now][ch[i]-'a']) 24 next[now][ch[i]-'a']=++cnt; 25 now=next[now][ch[i]-'a']; 26 sum[now]++; 27 } 28 pos=now; 29 } 30 void buildfail(){ 31 int head=0,tail=1; 32 q[0]=1,fail[1]=0; 33 while(head!=tail){ 34 int now=q[head];head++; 35 for(int i=0;i<26;i++){ 36 int v=next[now][i]; 37 if(!v) continue; 38 int k=fail[now]; 39 while(!next[k][i]) k=fail[k]; 40 fail[v]=next[k][i]; 41 q[tail++]=v; 42 } 43 } 44 for(int i=tail-1;i>=0;i--) 45 sum[fail[q[i]]]+=sum[q[i]];//就是这里啦!!! 46 } 47 }acm; 48 int n,pos[N]; 49 int main(){ 50 scanf("%d",&n); 51 for(int i=1;i<=n;i++) acm.ins(pos[i]); 52 acm.buildfail(); 53 for (int i=1;i<=n;i++) printf("%d\n",acm.sum[pos[i]]); 54 }