• P5231 [JSOI2012]玄武密码(SAM 经典运用)


    [JSOI2012]玄武密码

    题目背景

    在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河。相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中。老人们说,这是玄武神灵将天书藏匿在此。

    很多年后,人们终于在进香河地区发现了带有玄武密码的文字。更加神奇的是,这份带有玄武密码的文字,与玄武湖南岸台城的结构有微妙的关联。于是,漫长的破译工作开始了。

    题目描述

    经过分析,我们可以用东南西北四个方向来描述台城城砖的摆放,不妨用一个长度为 n n n 的序列 s s s 来描述,序列中的元素分别是 ESWN,代表了东南西北四向,我们称之为母串。而神秘的玄武密码是由四象的图案描述而成的 m m m 段文字。这里的四象,分别是东之青龙,西之白虎,南之朱雀,北之玄武,对东南西北四向相对应。

    现在,考古工作者遇到了一个难题。对于每一段文字 t t t,求出其最长的前缀 p p p,满足 p p p s s s 的子串。

    输入格式

    第一行有两个整数,分别表示母串的长度 n n n 和文字段的个数 m m m

    第二行有一个长度为 n n n 的字符串,表示母串 s s s

    接下来 m m m 行,每行一个字符串,表示一段带有玄武密码的文字 t t t

    输出格式

    对于每段文字,输出一行一个整数,表示最长的 p p p 的长度。

    样例 #1

    样例输入 #1

    7 3
    SNNSSNS
    NNSS
    NNN
    WSEE
    
    • 1
    • 2
    • 3
    • 4
    • 5

    样例输出 #1

    4
    2
    0
    
    • 1
    • 2
    • 3

    提示

    数据规模与约定

    • 对于 20 % 20\% 20% 的数据,保证 n ≤ 100 n \leq 100 n100 m ≤ 50 m \leq 50 m50
    • 对于 40 % 40\% 40% 的数据,保证 n ≤ 2 × 1 0 4 n \leq 2 \times 10^4 n2×104 m ≤ 2 × 1 0 3 m \leq 2 \times 10^3 m2×103
    • 对于 70 % 70\% 70% 的数据,保证 n ≤ 1 0 6 n \leq 10^6 n106 m ≤ 2 × 1 0 4 m \leq 2 \times 10^4 m2×104
    • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 1 0 7 1 \leq n \leq 10^7 1n107 1 ≤ m ≤ 1 0 5 1 \leq m \leq 10^5 1m105 1 ≤ ∣ t ∣ ≤ 100 1 \leq |t| \leq 100 1t100 s , t s, t s,t 中均只含字母 E S W N

    思路:

    由于后缀自动机形成的有向无环图恰好能够保存所有不同的子串,即从源点出发,沿任意一些字符能够到达的状态节点形成的子串在原字符串中都存在,故对于有每一个匹配串,都可以直接沿着后缀自动机形成的有向无环图走一遍,当无路可走或走完所有匹配串字符时即找到最长的前缀长度

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    //#define int long long
    const int N = 1e7 + 10, M = N << 1;
    int fa[M], ch[M][5], len[M];
    int tot = 1, np = 1;
    int n, m;
    char s[N], ss[110];
    int hah[26];
    
    void extend(int c) {
        int p = np;
        np = ++tot;
        len[np] = len[p] + 1;
    
        while (p && !ch[p][c]) {
            ch[p][c] = np;
            p = fa[p];
        }
        if (!p) {
            fa[np] = 1;
        }
        else {
            int q = ch[p][c];
            if (len[q] == len[p] + 1) {
                fa[np] = q;
            }
            else {
                int nq = ++tot;
                len[nq] = len[p] + 1;
                fa[nq] = fa[q], fa[q] = fa[np] = nq;
                while (p && ch[p][c] == q) {
                    ch[p][c] = nq;
                    p = fa[p];
                }
                memcpy(ch[nq], ch[q], sizeof ch[q]);
            }
        }
    }
    
    signed main()
    {
        hah['E' - 'A'] = 0, hah['S' - 'A'] = 1, hah['W' - 'A'] = 2, hah['N' - 'A'] = 3;
        scanf("%d%d", &n, &m);
        scanf("%s", s);
        for (int i = 0; s[i]; ++i) {
            extend(hah[s[i] - 'A']);
        }
        while (m--) {
            scanf("%s", ss);
            int nod = 1, cnt = 0;
            for (int i = 0; ss[i]; ++i) {
                if (!ch[nod][hah[ss[i] - 'A']]) {
                    break;
                }
                nod = ch[nod][hah[ss[i] - 'A']];
                ++cnt;
            }
            printf("%d\n", cnt);
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    基于51单片机出租车计费设计(proteus仿真+程序+原理图+设计说明书)
    9.2 运用API实现线程同步
    Python考前复习
    第53期|GPTSecurity周报
    Room+ViewModel+AsyncListDiffer【android JetPack】
    springboot 四大组件
    在VirtualBox中运行Ubuntu虚拟机小技巧:通过COMFAST CF-822AC无线USB网卡联网
    asp.net酒店餐饮管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
    <<Java>> 关于进程的那些事
    MyBatis实现MySQL表字段及结构的自动增删
  • 原文地址:https://blog.csdn.net/Jacob0824/article/details/126062857