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

    题目链接:BZOJ - 3172

    题目分析:

      题目要求求出每个单词出现的次数,如果把每个单词都在AC自动机里直接跑一遍,复杂度会很高。

      这里使用AC自动机的“副产品”——Fail树,Fail树的一个性质是,一个字符串出现的次数,就等于以它的结点为根的Fail树中的子树中所有结点的 Cnt 和。

      所以把每个单词插入的时候每个字符都 ++Cnt ,在建 Fail 的时候将结点依次压入一个栈,最后再从栈顶开始弹栈,更新栈顶元素的 Fail 的 Cnt 值,这样就是自叶子节点向上更新了。

      我开始写的时候出现的错误:建 Fail 的时候漏掉了 if (Now -> Child[i] == NULL) Now -> Child[i] = Now -> Fail -> Child[i]; 这句。这样会 RE !

    代码如下:

      

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
     
    using namespace std;
     
    const int MaxN = 200 + 5, MaxL = 1000000 + 5, MaxC = 26;
     
    int n, l;
     
    char Str[MaxL];
     
    struct Trie 
    {
        int Cnt;
        Trie *Fail, *Child[MaxC];
        void clear() {
            Cnt = 0;
            Fail = NULL;
            for (int i = 0; i < 26; ++i) Child[i] = NULL;
        }
    } TA[MaxL], *P = TA, *Root, *Zero, *Pos[MaxN];
     
    Trie *NewNode() {
        ++P;
        P -> clear();
        return P;
    }
     
    void AC_Init() {
        Zero = NewNode();
        Root = NewNode();
        Root -> Fail = Zero;
        for (int i = 0; i < 26; ++i) Zero -> Child[i] = Root;
    }
     
    Trie *Insert(char *Str, int l) {
        Trie *Now = Root;
        int t;
        for (int i = 0; i < l; ++i) {
            t = Str[i] - 'a';
            if (Now -> Child[t] == NULL) Now -> Child[t] = NewNode();
            Now = Now -> Child[t];
            ++(Now -> Cnt);
        }
        return Now;
    }
     
    Trie *Q[MaxL], *S[MaxL];
    int Head, Tail, Top;
     
    void Build_Fail() { 
        Top = 0;
        Head = Tail = 0;
        Q[++Tail] = Root;
        Trie *Now;
        while (Head < Tail) {
            Now = Q[++Head];
            S[++Top] = Now;
            for (int i = 0; i < 26; ++i) {
                if (Now -> Child[i] == NULL) Now -> Child[i] = Now -> Fail -> Child[i];
                else { 
                    Now -> Child[i] -> Fail = Now -> Fail -> Child[i];
                    Q[++Tail] = Now -> Child[i];
                }
            }
        }
        while (Top) {
            Now = S[Top--];
            if (Now -> Fail != NULL) 
                (Now -> Fail -> Cnt) += (Now -> Cnt);
        }
    }
     
    int main() 
    {
        scanf("%d", &n);
        AC_Init();
        for (int i = 1; i <= n; ++i) {
            scanf("%s", Str);
            l = strlen(Str);
            Pos[i] = Insert(Str, l);
        }
        Build_Fail();
        for (int i = 1; i <= n; ++i) printf("%d
    ", Pos[i] -> Cnt);
        return 0;
    }
    

      

      

  • 相关阅读:
    VTK 体绘制讨论_光照&阴影、VTKLODProp3D
    VTK 体绘制讨论_颜色传输函数
    VTK 体绘制讨论_梯度不透明度传输函数
    VTK 体绘制讨论_不透明度传输函数
    VTK 体绘制裁剪_Cripping技术
    VTK 体绘制裁剪_Cropping技术
    VTK 纹理映射体绘制_三维纹理映射
    VTK 纹理映射体绘制_二维纹理映射
    VTK 体绘制_固定点光线投影体绘制与GPU加速光线投影体绘制
    VTK 体绘制_光线投影+最大密度投影+等值面法
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4160894.html
Copyright © 2011-2022 走看看