Description



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


Input



第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6


Output



输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。


Sample Input


3

a

aa

aaa


Sample Output


6

3

1


直接构造trie和AC自动机(fail树)


然后把文章拼出来,然后在AC自动机上,分别统计每个单词的出现次数


但这个方法很慢


实际上可以用前缀和思想,从fail树从下往上累加,省去了最慢的查询



[TJOI2013]单词_#include[TJOI2013]单词_Trie_02


1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 #include<queue>
7 using namespace std;
8 const int N=1e6+205;
9 char s[N];
10 int Q[N];
11 int val[N],ch[N][28],size,f[N],n,mp[205],cnt[N];
12 void insert(int len,int id)
13 {int i;
14 int now=0;
15 for (i=0;i<len;i++)
16 {
17 if (ch[now][s[i]-'a']==0) ch[now][s[i]-'a']=++size;
18 now=ch[now][s[i]-'a'];
19 cnt[now]++;
20 }
21 mp[id]=now;
22 }
23 void AC_build()
24 {int i,h,t;
25 h=0;t=0;
26 for (i=0;i<26;i++)
27 if (ch[0][i]) f[ch[0][i]]=0,Q[++t]=ch[0][i];
28 while (h<t)
29 {
30 h++;
31 int u=Q[h];
32 for (i=0;i<26;i++)
33 {
34 if (ch[u][i])
35 {
36 f[ch[u][i]]=ch[f[u]][i];Q[++t]=ch[u][i];
37 }
38 else ch[u][i]=ch[f[u]][i];
39 }
40 }
41 for (i=t;i>=1;i--)
42 cnt[f[Q[i]]]+=cnt[Q[i]];
43 }
44 int main()
45 {int i,len,j;
46 cin>>n;
47 for (i=1;i<=n;i++)
48 {
49 scanf("%s",s);
50 len=strlen(s);
51 insert(len,i);
52 }
53 AC_build();
54 for (i=1;i<=n;i++)
55 printf("%d\n",cnt[mp[i]]);
56 }

View Code优化后


[TJOI2013]单词_#include[TJOI2013]单词_Trie_02


1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 #include<queue>
7 using namespace std;
8 queue<int>Q;
9 const int N=1e6+205;
10 char T[N],s[N];
11 int ans[205],val[N],ch[N][28],size,f[N],cnt,n,mp[205];
12 void insert(int len,int id)
13 {int i;
14 int now=0;
15 for (i=0;i<len;i++)
16 {
17 if (ch[now][s[i]-'a']==0) ch[now][s[i]-'a']=++size;
18 now=ch[now][s[i]-'a'];
19 }
20 if (val[now]==0)
21 val[now]=id,mp[id]=id;
22 else mp[id]=val[now];
23 }
24 void AC_build()
25 {int i;
26 for (i=0;i<27;i++)
27 if (ch[0][i]) f[ch[0][i]]=0,Q.push(ch[0][i]);
28 while (Q.empty()==0)
29 {
30 int u=Q.front();
31 Q.pop();
32 for (i=0;i<27;i++)
33 {
34 if (ch[u][i]) f[ch[u][i]]=ch[f[u]][i],Q.push(ch[u][i]);
35 else ch[u][i]=ch[f[u]][i];
36 }
37 }
38 }
39 void query()
40 {int i,j;
41 int now=0,len=strlen(T);
42 for (i=0;i<len;i++)
43 {
44 now=ch[now][T[i]-'a'];
45 for (j=now;j;j=f[j])
46 if (val[j])
47 ans[val[j]]++;
48 //cout<<i<<' '<<val[j]<<endl;
49 }
50 }
51 int main()
52 {int i,len,j;
53 cin>>n;
54 cnt=-1;
55 for (i=1;i<=n;i++)
56 {
57 scanf("%s",s);
58 len=strlen(s);
59 insert(len,i);
60 T[++cnt]='a'+26;
61 for (j=0;j<len;j++)
62 T[++cnt]=s[j];
63 //T[++cnt]='a'+26;
64 }
65 AC_build();
66 query();
67 for (i=1;i<=n;i++)
68 printf("%d\n",ans[mp[i]]);
69 }

View Code1