zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 数的统计
    Java实现 蓝桥杯VIP 算法训练 和为T
    Java实现 蓝桥杯VIP 算法训练 友好数
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 暗恋
    Java实现 蓝桥杯VIP 算法训练 暗恋
    测试鼠标是否在窗口内,以及测试鼠标是否在窗口停留
    RichEdit 各个版本介绍
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5647720.html
Copyright © 2011-2022 走看看