• P5231 [JSOI2012]玄武密码


    P5231 [JSOI2012]玄武密码

    链接

    分析:

      首先对所有询问串建立AC自动机,然后扫描一遍母串,在AC自动机上走,没走到一个点,标记这个点走过了,并且它的fail树上的祖先节点也可以访问到(即可以匹配到主串),于是沿着fail树打标记,当到一个已经打过标记的点的时候,退出。这样保证每个点只会被打标机一次。询问时,在AC自动机上倒着往前走,走到第一个打过标记的点的时候,从AC自动机的根节点到这个点的距离就是答案。复杂度$O(N+100M)$。

    代码: 

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int SZ = 10000005, N = 100005;
    int id[105], len[N], pos[N], ch[SZ][4], fa[SZ], q[SZ], fail[SZ], Index;
    bool vis[SZ];
    char s[SZ], t[105];
    
    void Insert(char *s,int k) {
        int u = 0;
        for (int i = 1; i <= len[k]; ++i) {
            int c = id[(int)s[i]];
            if (!ch[u][c]) ch[u][c] = ++Index, fa[Index] = u;
            u = ch[u][c];
        }
        pos[k] = u;
    }
    void bfs() {
        int L = 1, R = 0;
        for (int i = 0; i <= 3; ++i) if (ch[0][i]) q[++R] = ch[0][i];
        while (L <= R) {
            int u = q[L ++];
            for (int c = 0; c <= 3; ++c) {
                int v = ch[u][c];
                if (!v) ch[u][c] = ch[fail[u]][c];
                else fail[v] = ch[fail[u]][c], q[++R] = v;
            }
        }
    }
    int Calc(int x) {
        int ans = len[x];
        for (int i = pos[x]; i; i = fa[i], ans --) 
            if (vis[i]) return ans;
    }
    int main() {
        int n = read(), m = read();
        id['E'] = 0, id['S'] = 1, id['W'] = 2, id['N'] = 3;
        scanf("%s", s + 1);
        for (int i = 1; i <= m; ++i) {
            scanf("%s", t + 1);
            len[i] = strlen(t + 1);
            Insert(t, i);
        }
        bfs();
        int u = 0, v;
        for (int i = 1; i <= n; ++i) {
            int c = id[(int)s[i]];
            u = ch[u][c];
            v = u;
            while (v && !vis[v]) vis[v] = 1, v = fail[v];
        }
        for (int i = 1; i <= m; ++i) 
            printf("%d
    ", Calc(i));
        return 0;
    }
  • 相关阅读:
    出现socket:(10107)系统调用失败
    JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
    获取滚动条距离底部的距离
    linux常用命令使用方法
    Python:一
    【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
    【【C++ Primer 第15章】 虚析构函数
    ubuntu基本用法
    深度优先搜索(DFS)和广度优先搜索(BFS)
    【C++ Primer 第7章】定义抽象数据类型
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10468219.html
Copyright © 2020-2023  润新知