[TJOI2013]单词

Posted Z-Y-Y-S

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[TJOI2013]单词相关的知识,希望对你有一定的参考价值。

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树从下往上累加,省去了最慢的查询
技术分享图片
 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优化后
技术分享图片
 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

以上是关于[TJOI2013]单词的主要内容,如果未能解决你的问题,请参考以下文章

#3831 TJOI2013单词

bzoj3172 [Tjoi2013]单词

BZOJ 3172: [Tjoi2013]单词

P3966 [TJOI2013]单词

[TJOI2013]单词

[Bzoj3172][Tjoi2013]单词(fail树)