• 题解 [JSOI2012]玄武密码


    题意:给出一个文本串和(n)个模式串,求对于每个模式串,其前缀在文本串上的最大匹配长度。

    离线。

    先给模式串建出 AC 自动机,然后在 AC 自动机上查询文本串,对到达的每个节点跳失配指针,给能跳到的节点打上标记。

    对于每个模式串,它在 AC 自动机上遍历到的节点如果被打了标记,当前的前缀就是匹配的。找出最大的即可。

    代码

    #include<bits/stdc++.h>
    #define eps 1e-7
    #define re register
    #define N 2001001
    #define MAX 2001
    #define PI 3.1415927
    #define inf 1e18
    using namespace std;
    typedef long long ll;
    typedef double db;
    const ll mod=998244353;
    inline void read(re ll &ret)
    {
        ret=0;re ll pd=0;re char c=getchar();
        while(!isdigit(c)){pd|=c=='-';c=getchar();}
        while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
        ret=pd?-ret:ret;
        return;
    }
    ll n,m,trie[N][5],nxt[N],tot;
    bool b[N];
    inline ll calc(re char c)
    {
        switch(c)
        {
            case 'E':
                return 1;
            case 'S':
                return 2;
            case 'W':
                return 3;
            default :
                return 4;
        }
    }
    char s[10000001],a[100001][101];
    inline void insert(re ll pos)
    {
        re ll p=0,len=strlen(a[pos]+1);
        for(re int i=1;i<=len;i++)
        {
            re ll c=calc(a[pos][i]);
            if(!trie[p][c])
                trie[p][c]=++tot;
            p=trie[p][c];
        }
        return;
    }
    queue<ll>q;
    inline void bfs()
    {
        while(!q.empty())q.pop();
        for(re int i=1;i<=4;i++)
            if(trie[0][i])
                q.push(trie[0][i]);
        while(!q.empty())
        {
            re ll p=q.front();
            q.pop();
            for(re int i=1;i<=4;i++)
            {
                if(!trie[p][i])trie[p][i]=trie[nxt[p]][i];
                else
                {
                    q.push(trie[p][i]);
                    nxt[trie[p][i]]=trie[nxt[p]][i];
                }
            }
        }
        return;
    }
    inline void find()
    {
        re ll len=strlen(s+1),p=0;
        for(re int i=1;i<=len;i++)
        {
            re char c=calc(s[i]);
            p=trie[p][c];
            re ll k=p;
            while(k)
            {
                b[k]=true;
                k=nxt[k];
            }
        }
        return;
    }
    inline ll solve(re ll pos)
    {
        re ll len=strlen(a[pos]+1),p=0,ans=0;
        for(re int i=1;i<=len;i++)
        {
            re ll c=calc(a[pos][i]);
            p=trie[p][c];
            if(b[p])
                ans=i;      
        }
        return ans;
    }
    int main()
    {
        read(n);
        read(m);
        scanf("%s",s+1);
        for(re int i=1;i<=m;i++)
        {
            scanf("%s",a[i]+1);
            insert(i);
        }
        bfs();
        find();
        for(re int i=1;i<=m;i++)
            printf("%lld
    ",solve(i));
        exit(0);
    }
    
    
  • 相关阅读:
    Java 获取指定日期的方法总结
    【Struts2+Spring3+Hibernate3】SSH框架整合实现CRUD_1.0
    struts2标签Iterator迭代时获取下标
    【转】svn 修改log信息
    pppoe移植到arm上 2.0
    镜像制作
    proc增加节点的一个例子
    libcurl库的使用
    sed & awk Manuals
    用一个函数保存文件
  • 原文地址:https://www.cnblogs.com/CelticBlog/p/13531973.html
Copyright © 2020-2023  润新知