• [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
    ",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
    ",ans[mp[i]]);
    69 }
    View Code1
  • 相关阅读:
    Codeforces 231E
    Practice 15.07.07 计算几何
    Codeforces 552E
    Topcoder SRM 661 (Div.1) 250 MissingLCM
    HDU 4971
    Codeforces Round #306 (Div. 2)
    URAL 1988
    URAL 2032
    ServiceStack.Ormlit 事务
    ServiceStack.Ormlit 使用Insert的时候自增列不会被赋值
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8439233.html
Copyright © 2020-2023  润新知