zoukankan      html  css  js  c++  java
  • 玄武密码(bzoj4327)(JSOI2012)

    题目描述

    原题来自:JSOI 2012

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

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

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

    现在,考古工作者遇到了一个难题。对于每一段文字,其前缀在母串上的最大匹配长度是多少呢?

    输入格式

    第一行有两个整数,NNN 和 MMM,分别表示母串的长度和文字段的个数;
    第二行是一个长度为 NNN 的字符串,所有字符都满足是 ESW 和 N 中的一个;
    之后 MMM 行,每行有一个字符串,描述了一段带有玄武密码的文字。依然满足,所有字符都满足是 ESW 和 N 中的一个。

    输出格式

    输出有 MMM 行,对应 MMM 段文字。
    每一行输出一个数,表示这一段文字的前缀与母串的最大匹配串长度。

    样例

    样例输入

    7 3
    SNNSSNS
    NNSS
    NNN
    WSEE

    样例输出

    4
    2
    0

    数据范围与提示

    对于全部数据,1≤N≤10^7,1≤M≤10^5,保证每一段文字的长度均小于等于 100


    题目描述和题其实莫得关系
    上来很自然的想到了KMP
    然后发现O(n*100m)会T
    然后发现了AC自动机的正解,很SB的写了一上午(最主要的是教练一直说这次初赛分数线提高了,慌得一批)
    首先我们建树,然后把主串放在上面跑,很显然,对于每一个前缀如果能够成功匹配,那么它的nxt肯定也可以
    对于每一个可以匹配的地方,我们标记一次,最后对于每一个模式串都从后往前跑一遍,当我们发现一个地方被标记后,就输出答案(从后往前跑所找到的第一个一定是最长的能匹配的前缀)
    还有就是这道题的数据范围很迷,数组一定要开够
    下面给出代码:
     
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    using namespace std;
    inline int rd(){
        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;
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    int n,m;
    char s[10000006],a[106];
    int trie[1000006][4];
    int len[100006],f[10000006];
    int vis[10000006];
    int tot=1;
    int calc(char ch){
        if(ch=='E') return 0;
        if(ch=='W') return 1;
        if(ch=='N') return 2;
        if(ch=='S') return 3;
    }
    void pre(int x){
        int c=1;
        for(int i=1;i<=len[x];i++){
            int h=calc(a[i]);
            if(!trie[c][h]){
                f[++tot]=c;
                trie[c][h]=tot;
            }
            c=trie[c][h];
        }
        vis[x]=c;
        return ;
    }
    int q[1000006];
    int l=0,r=0;
    int nxt[1000006];
    void get_next(){
        q[++r]=1;
        for(int i=0;i<=3;i++) trie[0][i]=1;
        nxt[1]=0;
        while(l<r){
            int h=q[++l];
            for(int i=0;i<=3;i++){
                if(!trie[h][i]) trie[h][i]=trie[nxt[h]][i];
                else{
                    nxt[trie[h][i]]=trie[nxt[h]][i];
                    q[++r]=trie[h][i];
                }
            }
        }
        return ;
    }
    bool book[1000006];
    void solve(){
        int c=1;
        for(int i=1;i<=n;i++){
            int h=calc(s[i]);
            c=trie[c][h];
            for(int j=c;j;j=nxt[j]){
                if(book[j]) break;
                book[j]=1;
            }
        }
        return ;
    }
    int gets(int x){
        int ans=len[x];
        for(int i=vis[x];i;i=f[i],ans--) if(book[i]) return ans;
    }
    int main(){
        n=rd(),m=rd();
        scanf("%s",s+1);
        for(int i=1;i<=m;i++){
            scanf("%s",a+1);
            len[i]=strlen(a+1);
            pre(i);
        }
        get_next();
        solve();
        for(int i=1;i<=m;i++) printf("%d
    ",gets(i));
        return 0;
    }
    蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
  • 相关阅读:
    js可拖拽的div
    hightcharts 3d 堆积图下钻
    绝对炫的3D幻灯片-SLICEBOX
    td在relative模式下,IE9不显示border
    IE9 打不开界面也不报错,只有打开控制台才会显示
    display inline-block 垂直居中
    css实现div的高度填满剩余空间
    g2g c u l8r(训练赛)
    Binarize It(训练赛)
    C. Maximum width(贪心)
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/9749628.html
Copyright © 2011-2022 走看看