在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河。相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中。老人们说,这是玄武神灵将天书藏匿在此。
很多年后,人们终于在进香河地区发现了带有玄武密码的文字。更加神奇的是,这份带有玄武密码的文字,与玄武湖南岸台城的结构有微妙的关联。于是,漫长的破译工作开始了。
经过分析,我们可以用东南西北四个方向来描述台城城砖的摆放,不妨用一个长度为N的序列来描述,序列中的元素分别是‘E’,‘S’,‘W’,‘N’,代表了东南西北四向,我们称之为母串。而神秘的玄武密码是由四象的图案描述而成的M段文字。这里的四象,分别是东之青龙,西之白虎,南之朱雀,北之玄武,对东南西北四向相对应。
现在,考古工作者遇到了一个难题。对于每一段文字,其前缀在母串上的最大匹配长度是多少呢?
第一行有两个整数,N和M,分别表示母串的长度和文字段的个数。
第二行是一个长度为N的字符串,所有字符都满足是E,S,W和N中的一个。
之后M行,每行有一个字符串,描述了一段带有玄武密码的文字。依然满足,所有字符都满足是E,S,W和N中的一个。
输出有M行,对应M段文字。
每一行输出一个数,表示这一段文字的前缀与母串的最大匹配串长度。
1 #include<bits/stdc++.h>
2 #define il inline
3 #define ll long long
4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
6 using namespace std;
7 const int N=1000005;
8 int n,m,trie[N][4],cnt,ed[N],fail[N],dep[N],pre[N];
9 char t[N*10],s[N];
10 bool vis[N];
11
12 il int id(char c){
13 if(c==‘E‘)return 0;
14 if(c==‘S‘)return 1;
15 if(c==‘W‘)return 2;
16 return 3;
17 }
18
19 il void insert(char *s,int num){
20 int len=strlen(s),p=0,x;
21 For(i,0,len-1){
22 x=id(s[i]);
23 if(!trie[p][x])dep[++cnt]=dep[p]+1,trie[p][x]=cnt,pre[cnt]=p;
24 p=trie[p][x];
25 }
26 ed[num]=p;
27 }
28
29 il void bfs(){
30 queue<int>q;
31 For(i,0,3)if(trie[0][i])q.push(trie[0][i]);
32 while(!q.empty()){
33 int u=q.front();q.pop();
34 For(i,0,3) {
35 int v=trie[u][i];
36 if(v) fail[v]=trie[fail[u]][i],q.push(v);
37 else trie[u][i]=trie[fail[u]][i];
38 }
39 }
40 }
41
42 il int dfs(int now){
43 if(vis[now])return dep[now];
44 if(!now) return 0;
45 dfs(pre[now]);
46 }
47
48 il void search(char *s){
49 int len=strlen(s),p=0;
50 For(i,0,len-1){
51 p=trie[p][id(s[i])];
52 for(int j=p;j&&!vis[j];j=fail[j]) vis[j]=1;
53 }
54 For(i,1,m) printf("%d\n",dfs(ed[i]));
55 }
56
57 int main(){
58 scanf("%d%d%s",&n,&m,t);
59 For(i,1,m) scanf("%s",s),insert(s,i);
60 bfs();
61 search(t);
62 return 0;
63 }