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

[BZOJ4327] JSOI2012玄武密码

2017-12-14 10:15 471 查看
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。

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

SAM模板题。

注意开两倍空间。

#include <bits/stdc++.h>
#define N 10000010
#define M 110
using namespace std;
int n,m,to[M];
char s
,z[M];
struct node{
node *ch[4],*fail;
int dep;
}t[N<<1],*root=t,*tail=t;

node *newnode(){
(++tail)->fail=t;
tail->ch[0]=tail->ch[1]=tail->ch[2]=tail->ch[3]=t;
return tail;
}

node* add(node *p,int c){
node *cur=newnode(),*q=t,*f;
cur->dep=p->dep+1;
for (node *i=p;i!=t;i=i->fail){
if (i->ch[c]!=t){
f=i; q=i->ch[c];
break;
}
i->ch[c]=cur;
}
if (q==t){
cur->fail=root;
return cur;
}
if (q->dep==f->dep+1)
cur->fail=q;
else{
node *nq=newnode();
nq->fail=q->fail;
cur->fail=q->fail=nq;
for (node *i=f;i!=t && i->ch[c]==q;i=i->fail)
i->ch[c]=nq;
for (int i=0;i<4;i++)
nq->ch[i]=q->ch[i];
}
return cur;
}

void build(){
(root=newnode())->dep=0;
to['E']=0,to['S']=1,to['W']=2,to['N']=3;
node *las=root;
for (int i=0;i<n;i++)
las=add(las,to[s[i]]);
}

int main(){
scanf("%d%d",&n,&m);
scanf(" %s",s);
build();
int len,ans; node *cur;
for (int i=1;i<=m;i++){
scanf(" %s",z);
ans=0,len=strlen(z);
cur=root;
for (int j=0;j<len;ans++,j++){
cur=cur->ch[to[z[j]]];
if (cur==t) break;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  SAM bzoj