zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      题目传送门

    玄武密码

    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。

     


      分析:

      AC自动机的好题。

      建Trie树的时候记录一下每个节点的父节点和每一段模式串的终点,然后建立$fail$指针再跑一边文本串,再经过了的节点打上标记,然后对每一个模式串询问,从终点一直往根节点跳,只要遇到打上标记的点就直接返回答案(也就是该模式串总长减去遍历经过的节点数)。

      Code:

    //It is made by HolseLee on 13rd Aug 2018
    //BZOJ4327
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e7+7;
    const int M=101;
    const int maxn=5e5+7;
    int n,m,tot,fail[maxn],fa[maxn],point[maxn],lo[maxn/5];
    char s[N],a[M];
    struct Node{
        int nxt[4];bool vis;
    }t[maxn];
    queue<int>team;
    
    struct Trie{
    
        int get(char ch)
        {
            if(ch=='E')return 0;
            if(ch=='S')return 1;
            if(ch=='W')return 2;
            if(ch=='N')return 3;
        }
    
        void ins(char *ch,int x)
        {
            int root=0,k,len=strlen(ch);
            for(int i=0;i<len;++i){
                k=get(ch[i]);
                if(!t[root].nxt[k])
                    t[root].nxt[k]=++tot,
                    fa[t[root].nxt[k]]=root;
                root=t[root].nxt[k];
            }
            point[x]=root;
        }
    
        void getfail()
        {
            int root=0;
            for(int i=0;i<4;++i){
                if(t[root].nxt[i])
                fail[t[root].nxt[i]]=0,
                team.push(t[root].nxt[i]);
            }
            while(!team.empty()){
                root=team.front();team.pop();
                for(int i=0;i<4;++i)
                if(t[root].nxt[i]){
                    fail[t[root].nxt[i]]=t[fail[root]].nxt[i];
                    team.push(t[root].nxt[i]);
                }
                else t[root].nxt[i]=t[fail[root]].nxt[i];
            }
        }
    
        void pre()
        {
            for(int i=0;i<=tot;++i)t[i].vis=false;
            int root=0,id;
            for(int i=0;i<n;++i){
                id=get(s[i]);
                root=t[root].nxt[id];
                for(int j=root;j;j=fail[j])
                    if(t[j].vis)break;
                    else t[j].vis=1;
            }
        }
    
        int quary(int x)
        {
            int ret=lo[x];
            for(int i=point[x];i;i=fa[i]){
                if(t[i].vis)return ret;
                ret--;
            }
            return 0;
        }
    }T;
    
    int main()
    {
        scanf("%d%d%s",&n,&m,s);
        for(int i=1;i<=m;++i){
            scanf("%s",a);
            lo[i]=strlen(a);
            T.ins(a,i);
        }
        T.getfail();T.pre();
        for(int i=1;i<=m;++i)
        printf("%d
    ",T.quary(i));
        return 0;
    }
  • 相关阅读:
    js根据年份获取某月份有几天
    java 时间转换去杠
    简单Maven Dos命令语句
    Maven命令参数
    Redis学习推荐
    Java中Redis缓存
    oracle新建登录用户sql语句
    ORacle修改表列长度
    jsp利用application统计在线人数的方法
    Oracle之分页查询
  • 原文地址:https://www.cnblogs.com/cytus/p/9471414.html
Copyright © 2011-2022 走看看