zoukankan      html  css  js  c++  java
  • HDU 2222 AC自动机

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2222.

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cctype>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <map>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <set>
    #define X first
    #define Y second
    #define sqr(x) (x)*(x)
    #pragma comment(linker,"/STACK:102400000,102400000")
    using namespace std;
    const double PI = acos(-1.0);
    map<int, int>::iterator it;
    typedef long long LL ;
    template<typename T> void checkmin(T &x, T y) {x = min(x, y);}
    template<typename T> void checkmax(T &x, T y) {x = max(x, y);}
    
    //MAX_NODE = StringNumber * StringLength
    const int MAX_NODE = 500000 + 50;
    //节点个数,一般字符形式的题26个
    const int CHILD_NUM = 26;
    //特定题目需要
    const int mod = 20090717;
    
    class ACAutomaton {
        private:
            //每个节点的儿子,即当前节点的状态转移
            int chd[MAX_NODE][CHILD_NUM];
            //记录题目给的关键数据
            int val[MAX_NODE];
            //传说中的fail指针
            int fail[MAX_NODE];
            //队列,用于广度优先计算fail指针
            int Q[MAX_NODE];
            //字母对应的ID
            int ID[128];
            //已使用节点个数
            int sz;
        public:
            //初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
            void Initialize() {
                fail[0] = 0;
                for(int i = 0 ; i < CHILD_NUM ; i ++) {
                    ID[i+'a'] = i;
                }
            }
            //重新建树需先Reset
            void Reset() {
                memset(chd[0] , -1 , sizeof(chd[0]));
                sz = 1;
            }
            //将权值为key的字符串a插入到trie中
            void Insert(char *a, int key) {
                int p = 0;
                for(; *a ; ++ a) {
                    int c = ID[*a];
                    if(chd[p][c] == -1) {
                        memset(chd[sz] , -1 , sizeof(chd[sz]));
                        val[sz] = 0;
                        chd[p][c] = sz ++;
                    }
                    p = chd[p][c];
                }
    
                val[p] += key;
            }
            //建立AC自动机,确定每个节点的权值以及状态转移
            void Construct() {
                int *s = Q , *e = Q;
                for(int i = 0 ; i < CHILD_NUM ; i ++) {
                    if(~chd[0][i]) {
                        fail[ chd[0][i] ] = 0;
                        *e ++ = chd[0][i];
                    }
                }
                while(s != e) {
                    int r = *s++;
                    for(int i = 0 ; i < CHILD_NUM ; i ++) {
                        int u = chd[r][i];
                        if(~u) {
                            *e ++ = u;
                            int v = fail[r];
                            while(chd[v][i] == -1 && v)v = fail[v];
    
                            fail[u] = chd[v][i] == -1 ? 0 : chd[v][i];
                        }
                    }
                }
            }
            //询问所给字符串包含多少个模式串
            int Query(char *s) {
                int q = 0;
                int ret = 0;
                for(; *s; ++s) {
                    int c = ID[*s];
                    while(chd[q][c] == -1 && q)q = fail[q];
                    q = chd[q][c];
                    if(q == -1)q = 0;
                    int p = q;
                    while(p) {
                        if(val[p]) {
                            ret += val[p];
                            val[p] = 0;
                        }
                        else {
                            break;
                        }
                        p = fail[p];
                    }
                }
                return ret;
            }
    } AC;
    
    char s[1000005], t[10005];
    int main() {
        int T;
        AC.Initialize();
        scanf("%d", &T);
        while(T--) {
            AC.Reset();
            int n;
            scanf("%d", &n);
            for(int i = 0; i < n; ++i) {
                scanf("%s", t);
                AC.Insert(t, 1);
            }
            AC.Construct();
            scanf("%s", s);
            int res = AC.Query(s);
            printf("%d
    ", res);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    zabbix笔记之zabbix-agent 安装
    Bat脚本处理ftp超强案例解说
    tidb集群部署
    NPM是node.js软件包的管理器
    一、安装vue-cli(当前版本是4.x)(只需安装一次,后面永久使用)
    二十四、ref获取DOM
    二十三、watch监听
    二十二、computed计算属性
    二十一、todolist案例开发
    二十、双向绑定原理
  • 原文地址:https://www.cnblogs.com/cxw199204/p/3384409.html
Copyright © 2011-2022 走看看