zoukankan      html  css  js  c++  java
  • 【AC自动机】bzoj3172: [Tjoi2013]单词

    fail图上后缀和需要注意一下

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    a
    aa
    aaa

    Sample Output

    6
    3
    1

    题目分析

    考虑暴力:将每一个单词作为文本串匹配,一旦遇到一个单词节点,就向上跳fail统计整条链上的所有单词的贡献。

    注意到对于每一个匹配到的单词节点,有一个向上的后缀和的形式在这里。

    那么从另一个方式考虑,对于每一个节点,计算有多少子节点会把它统计进答案里。

    这样就可以用很自然的fail后缀和来处理这个问题了。

    注意

    要注意的是,trie图后缀和的统计顺序不能够简单地根据tot...1的顺序。

    因为trie图是有分叉的,节点的标号与深度并无关系。

     1 #include<bits/stdc++.h>
     2 const int maxn = 203;
     3 const int maxNode = 1000035;
     4 
     5 struct ACAutomaton
     6 {
     7     char s[maxn];
     8     int vis[maxNode];
     9     std::queue<int> q;
    10     int stk[maxNode],cnt;
    11     int fail[maxNode],f[maxNode][30],size[maxNode],tot,n;
    12     void insert(char *s, int t)
    13     {
    14         int u = 1, lens = strlen(s);
    15         for (int i=0; i<lens; i++)
    16         {
    17             int c = s[i]-'a';
    18             if (!f[u][c]) f[u][c] = ++tot;
    19             u = f[u][c], size[u]++;
    20         }
    21         vis[t] = u;
    22 //        vis[u]++;
    23     }
    24     void count()      //其实这里写的冗长了一点
    25     {             //如果用手写的队列就不用再开一个数组了
    26         for (int i=tot; i>1; i--)
    27             size[fail[stk[i]]] += size[stk[i]];
    28     }
    29     void build()
    30     {
    31         for (int i=0; i<=25; i++) f[0][i] = 1;
    32         q.push(1);
    33         while (q.size())
    34         {
    35             int tt = q.front();
    36             q.pop();
    37             stk[++cnt] = tt;
    38             for (int i=0; i<=25; i++)
    39                 if (f[tt][i])
    40                     fail[f[tt][i]] = f[fail[tt]][i], q.push(f[tt][i]);
    41                 else f[tt][i] = f[fail[tt]][i];
    42         }
    43     }
    44 }f;
    45 int n;
    46 char s[1000035]; 
    47 
    48 int main()
    49 {
    50     scanf("%d",&n);
    51     f.tot = 1;
    52     for (int i=1; i<=n; i++)
    53         scanf("%s",s), f.insert(s, i);
    54     f.build(), f.count();
    55     for (int i=1; i<=n; i++) printf("%d
    ",f.size[f.vis[i]]);
    56     return 0;
    57 }

    END

  • 相关阅读:
    php增加自动刷新当前页面
    liunx环境下安装mysql5.7及以上版本
    mysql的主从级联复制的配置
    windowns常用命令
    liunx之使用(mount)挂载技术
    在burpsuite中为什么不能选中设置好的代理?
    c++中向任意目录下写文件
    Hbase——JavaAPI操作笔记
    每周总结(6)(补)
    每周总结(5)
  • 原文地址:https://www.cnblogs.com/antiquality/p/9600758.html
Copyright © 2011-2022 走看看