• 4327: JSOI2012 玄武密码[SAM]


    4327: JSOI2012 玄武密码

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 263  Solved: 112
    [Submit][Status][Discuss]

    Description

    在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河。相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中。老人们说,这是玄武神灵将天书藏匿在此。 
    很多年后,人们终于在进香河地区发现了带有玄武密码的文字。更加神奇的是,这份带有玄武密码的文字,与玄武湖南岸台城的结构有微妙的关联。于是,漫长的破译工作开始了。 
    经过分析,我们可以用东南西北四个方向来描述台城城砖的摆放,不妨用一个长度为N的序列来描述,序列中的元素分别是‘E’,‘S’,‘W’,‘N’,代表了东南西北四向,我们称之为母串。而神秘的玄武密码是由四象的图案描述而成的M段文字。这里的四象,分别是东之青龙,西之白虎,南之朱雀,北之玄武,对东南西北四向相对应。 
    现在,考古工作者遇到了一个难题。对于每一段文字,其前缀在母串上的最大匹配长度是多少呢? 
     

    Input

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

    Output

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

    Sample Input

    7 3
    SNNSSNS
    NNSS
    NNN
    WSEE

    Sample Output

    4
    2
    0

    HINT

    对于100%的数据,N<=10^7,M<=10^5,每一段文字的长度<=100。


    应上传者要求,此题不公开,如有异议,请提出.


    Source

    给一个字符串 S,给一些字符串  si,求每个 si的最长的在 S 中出现过的前缀的长度。

     

    对 S 建立 SAM,将每个 si​​ 放在 SAM 上运行即可。

    #include<ctime>
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define OPT __attribute__((optimize("O2")))
    using namespace std;
    int n,m;
    struct S{
        int p,q,np,nq;
        int last,cnt;int len;
        static const int N=2e7;
        int fa[N],l[N],a[N][4];char ch[(N>>1)+5];
        S(){last=++cnt;}
        OPT inline int get(char &c){
            return c=='N'?0:
                   c=='S'?1:
                   c=='W'?2:
                   3;
        }
        OPT inline void extend(int c){
            p=last;np=last=++cnt;l[np]=l[p]+1;
            while(!a[p][c]&&p) a[p][c]=np,p=fa[p];
            if(!p) fa[np]=1;
            else{
                q=a[p][c];
                if(l[p]+1==l[q]) fa[np]=q;
                else{
                    nq=++cnt;l[nq]=l[p]+1;
                    memcpy(a[nq],a[q],sizeof a[q]);
                    fa[nq]=fa[q];
                    fa[np]=fa[q]=nq;
                    while(a[p][c]==q) a[p][c]=nq,p=fa[p];
                }
            }
        }
        OPT inline void build(){
            scanf("%s",ch);//len=strlen(ch);
            for(int i=0;i<len;i++) extend(get(ch[i]));
        }
        OPT inline void solve(){
            int ans=0;
            scanf("%s",ch);len=strlen(ch);
            for(int i=0,p=1;i<len;i++){
                if(a[p][get(ch[i])]){
                    p=a[p][get(ch[i])];
                    ans++;
                }
                else break;
            }
            printf("%d
    ",ans);
        }
    }sam;
    int main(){
        scanf("%d%d",&n,&m);sam.len=n;
        sam.build();
        for(int i=0;i<m;i++) sam.solve();
        return 0;
    }
  • 相关阅读:
    SCCM2012分发脚本
    MPIO配置
    创建快捷方式,修改注册表
    常用口语 一
    3463工厂频道预置方法
    xargs 主要用于不支持管道的shell命令*****
    RDA DEBUG
    linux shell 实例1
    MSD3458开发资料
    MSD6A628开发资料与技术支持
  • 原文地址:https://www.cnblogs.com/shenben/p/6800211.html
Copyright © 2020-2023  润新知