[BZOJ4327] [JSOI2012] 玄武密码

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。

 

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

 


 

 

每到一个节点,它跳fail指针一直调到根所经过的节点一定是可以匹配的节点。

所以对于询问串建trie树,记录每个串的结尾节点和每个节点的父亲节点。

然后AC自动机匹配的时候每到一个节点,就跳fail指针并打上标记,遇到打标记的点就退出,保证每个点只访问一遍。

然后处理询问就从串的结尾向上走遇到被标记的节点就退出。

 


 

 

 

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define reg register
inline int read() {
    int res=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
#define N 10000005
int n, m;
int nxt[N][5], fail[N], cnt;
int mark[N];
char str[N], stt[100005][105], len[100005];
int end[100005], fa[N];
inline int id(char c)
{
    if (c == 'N') return 1;
    if (c == 'S') return 3;
    if (c == 'W') return 2;
    return 4;
}

inline void ins(int i)
{
    len[i] = strlen(stt[i] + 1);
    int p = 1;
    int now = 0;
    while(p <= len[i]) 
    {
        if (!nxt[now][id(stt[i][p])]) nxt[now][id(stt[i][p])] = ++cnt, fa[cnt] = now;
        now = nxt[now][id(stt[i][p])];
        p++;
    }
    end[i] = now;
}

inline void AC_Match()
{
    queue <int> q;
    fail[0] = -1;
    for (reg int i = 1 ; i <= 4 ; i ++) if (nxt[0][i]) q.push(nxt[0][i]), fail[nxt[0][i]] = 0;
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for (reg int i = 1 ; i <= 4 ; i ++)
        {
            if (nxt[x][i]) fail[nxt[x][i]] = nxt[fail[x]][i], q.push(nxt[x][i]);
            else nxt[x][i] = nxt[fail[x]][i];
        }
    }
}

inline void AC_Auto()
{
    int p = 1, now = 0;
    while(p <= n) 
    {
        now = nxt[now][id(str[p])];
        int x = now;
        while(~x)
        {
            if (mark[x]) break;
            mark[x] = 1;
            x = fail[x];
        }
        p++;
    }
}

inline int solve(int x)
{
    int y = len[x];
    int now = end[x];
    while(now)
    {
        if (mark[now]) return y;
        y--;
        now = fa[now];
    }
    return 0;
}

int main() 
{
    n = read(), m = read();
    scanf("%s", str + 1);
    for (reg int i = 1 ; i <= m ; i ++)
    {
        scanf("%s", stt[i] + 1);
        ins(i);
    }
    AC_Match();
    AC_Auto();
    for (reg int i = 1 ; i <= m ; i ++) printf("%d\n", solve(i));
    return 0;
}

 

posted @ 2018-09-01 08:16  zZhBr  阅读(160)  评论(0编辑  收藏  举报