您的位置:首页 > Web前端 > JavaScript

BZOJ 4327: JSOI2012 玄武密码

2021-04-26 00:25 1151 查看

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。

 

Solution:

  本题AC自动机+简单搜索就好了。

  存下主串,再对所有模式串构建AC自动机(记录下每个串结尾的节点和每个节点的前趋以及深度),然后直接在trie树中查询主串,对于扫到的节点p,标记所有没访问过的fail[p]节点(访问过的就不用再往上标记了),然后直接从每个模式串的尾节点往上dfs,搜到的第一个被标记的节点的深度就是答案了。

代码:

#include#define il inline#define ll long long#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)using namespace std;const int N=1000005;int n,m,trie
[4],cnt,ed
,fail
,dep
,pre
;char t[N*10],s
;bool vis
;

il int id(char c){    if(c=='E')return 0;    if(c=='S')return 1;    if(c=='W')return 2;    return 3;
}

il void insert(char *s,int num){    int len=strlen(s),p=0,x;
    For(i,0,len-1){
        x=id(s[i]);        if(!trie

[x])dep[++cnt]=dep[p]+1,trie[p][x]=cnt,pre[cnt]=p;         p=trie[p][x];     }     ed[num]=p; } il void bfs(){     queue<int>q;     For(i,0,3)if(trie[0][i])q.push(trie[0][i]);    while(!q.empty()){        int u=q.front();q.pop();         For(i,0,3) {            int v=trie[u][i];            if(v) fail[v]=trie[fail[u]][i],q.push(v);            else trie[u][i]=trie[fail[u]][i];         }     } } il int dfs(int now){    if(vis[now])return dep[now];    if(!now) return 0;     dfs(pre[now]); } il void search(char *s){    int len=strlen(s),p=0;     For(i,0,len-1){         p=trie[p][id(s[i])];        for(int j=p;j&&!vis[j];j=fail[j]) vis[j]=1;     }     For(i,1,m) printf("%d\n",dfs(ed[i])); }int main(){     scanf("%d%d%s",&n,&m,t);     For(i,1,m) scanf("%s",s),insert(s,i);     bfs();     search(t);    return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: