zoukankan      html  css  js  c++  java
  • BZOJ3172:[TJOI2013]单词(AC自动机)

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    a
    aa
    aaa

    Sample Output

    6
    3
    1

    Solution

    还是对AC自动机的理解不够到位啊=-=……
    其实fail指针也是一颗树,而fail树有一些神奇的性质
    根节点仍然是0,每一个fail指针指向自己的最长后缀
    也就是说,我们把每个节点的权值设为1,然后再处理一下fail树的子树和
    如何处理呢?在build_fail的时候记录一下经过节点的顺序,
    然后倒序枚举,将当前枚举到的点的fail指针指向的点的权值累加一下
    最开始记录一下每个单词的位置,方便输出。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<queue>
     5 #define N (1000000+100)
     6 using namespace std;
     7 int Son[N][27],Fail[N],End[N];
     8 int n,sz,ans[N],pos[N],Q[N],cnt;
     9 bool vis[N],flag;
    10 char s[N],ask[N];
    11 queue<int>q;
    12 void Insert(char s[],int &pos)
    13 {
    14     int now=0,len=strlen(s);
    15     for (int i=0; i<len; ++i)
    16     {
    17         int x=s[i]-'a';
    18         if (!Son[now][x]) Son[now][x]=++sz;
    19         now=Son[now][x];
    20         ++ans[now];
    21     }
    22     pos=now;
    23 }
    24 
    25 void Build_Fail()
    26 {
    27     for (int i=0;i<26;++i)
    28         if (Son[0][i])
    29             q.push(Son[0][i]);
    30     while (!q.empty())
    31     {
    32         int now=q.front(); q.pop();
    33         Q[++cnt]=now;
    34         for (int i=0;i<26;++i)
    35         {
    36             if (!Son[now][i])
    37             {
    38                 Son[now][i]=Son[Fail[now]][i];
    39                 continue;
    40             }
    41             Fail[Son[now][i]]=Son[Fail[now]][i];
    42             q.push(Son[now][i]);
    43         }
    44     }    
    45 }
    46 
    47 void Query()
    48 {
    49     for (int i=cnt;i>=1;--i)
    50         ans[Fail[Q[i]]]+=ans[Q[i]];
    51     for (int i=1;i<=n;++i)
    52         printf("%d
    ",ans[pos[i]]);
    53 }
    54 int main()
    55 {
    56     scanf("%d",&n);
    57     for (int i=1;i<=n;++i)
    58         scanf("%s",s),Insert(s,pos[i]);
    59     Build_Fail();
    60     Query();
    61 }
  • 相关阅读:
    关于近期对于移动端开发的一些看法
    前端加密
    移动开发小知识大全
    介绍下京东的(选项卡中的选项卡)是怎么实现的
    一样的代码,一样的逻辑,不一样的效果(选项卡和轮播图)
    总结一下meta标签
    cookie的使用
    移动端常用代码
    上拉加载实现
    关于jQuery出现的新添加元素点击事件无效
  • 原文地址:https://www.cnblogs.com/refun/p/8685565.html
Copyright © 2011-2022 走看看