题解 [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\n",solve(i));
    exit(0);
}

posted @ 2020-08-19 21:17  CelticOIer  阅读(99)  评论(3编辑  收藏  举报