• BZOJ_3172_[TJOI2013]_单词_(AC自动机)


    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=3172

    (n)个单词组成一篇文章,求每个单词在文章中出现的次数.

    分析


    这道题很像BZOJ_2434_[NOI2011]_阿狸的打字机_(AC自动机+dfs序+树状数组)

    一个单词出现过,那么一定是某个单词的某个前缀的后缀,可以通过这个前缀的末尾沿着失配边找到它.我们要统计有多少点可以这样找到它.

    建立fail树,很显然,单词(x)子树中的所有点都可以沿着失配边找到(x),这样我们只用记录每个点有多少次就行了.

    (eg:如果文章是 a aa aaa,那么a有3次(三个单词各一次),aa有2次(第二个单词和第三个单词),aaa有1次(第三个单词)).

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e6+10,type=26;
     4 int n,m;
     5 char s[maxn];
     6 struct Aho_Corasick{
     7     int sz;
     8     int q[maxn],val[maxn],pos[maxn],f[maxn];
     9     int ch[maxn][type];
    10     Aho_Corasick():sz(0){memset(ch[0],0,sizeof ch[0]);memset(val,0,sizeof val);}
    11     inline int insert(char *s){
    12         int u=0,m=strlen(s+1);
    13         for(int i=1;i<=m;i++){
    14             int c=s[i]-'a';
    15             if(!ch[u][c]){
    16                 memset(ch[++sz],0,sizeof ch[sz]); val[sz]=0;
    17                 ch[u][c]=sz;
    18             }
    19             u=ch[u][c];
    20             val[u]++;
    21         }
    22         return u;
    23     }
    24     inline void get_fail(){
    25         int L=1,R=0;
    26         for(int c=0;c<type;c++){
    27             int u=ch[0][c];
    28             if(u){f[u]=0;q[++R]=u;}
    29         }
    30         while(L<=R){
    31             int u=q[L++];
    32             for(int c=0;c<type;c++){
    33                 int t=ch[u][c];
    34                 if(!t){ch[u][c]=ch[f[u]][c];continue;}
    35                 int v=f[u];
    36                 f[t]=ch[v][c];
    37                 q[++R]=t;
    38             }
    39         }
    40         for(int i=sz;i;i--) val[f[q[i]]]+=val[q[i]];
    41     }
    42     inline void solve(){
    43         for(int i=1;i<=n;i++) printf("%d
    ",val[pos[i]]);
    44     }
    45 }ac;
    46 inline void solve(){
    47     ac.get_fail();
    48     ac.solve();
    49 }
    50 inline void init(){
    51     scanf("%d",&n);
    52     for(int i=1;i<=n;i++){
    53         scanf("%s",s+1);
    54         ac.pos[i]=ac.insert(s);
    55     }
    56 }
    57 int main(){
    58     init();
    59     solve();
    60     return 0;
    61 }
    View Code

    3172: [Tjoi2013]单词

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 2837  Solved: 1356
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    a
    aa
    aaa

    Sample Output

    6
    3
    1

    HINT

    Source

  • 相关阅读:
    好玩的spring boot banner 图
    数据结构和算法二(数组)
    数据结构与算法三(链表)
    数据结构和算法一(基础知识)
    jenkins 部署node应用
    Docker-compose 安装Jenkins
    Docker 网络模式
    exe4j 转jar
    c#索引器的简单用法
    Adapter模式
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5647720.html
Copyright © 2020-2023  润新知