4327: JSOI2012 玄武密码
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 435 Solved: 194
[ Submit][ Status][ Discuss]
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
SNNSSNS
NNSS
NNN
WSEE
Sample Output
4
2
0
2
0
HINT
对于100%的数据,N<=10^7,M<=10^5,每一段文字的长度<=100。
应上传者要求,此题不公开,如有异议,请提出.
Source
直接建AC自动机然后把母串拿上去匹配打vis标记即可.然后一个字符串的最长匹配前缀就是最深被vis的点.
要把vis标记向fail传递.于是乎要用到基数排序来搞定拓扑关系.
#include<bits/stdc++.h>
using namespace std;
const int maxm = 1e7 + 5;
const int maxn = 1e5 + 5;
int n, m, tot, top;
bool vis[maxm];
char s[maxn][105], str[maxm];
int c[maxm][5], fail[maxm], mean[320], len[maxm], sa[maxm], cnt[maxm];
inline void insert(char* ss) {
int p = 0;
for (int i = 0; ss[i]; ++ i) {
int idx = mean[(int)ss[i]];
if (!c[p][idx]) c[p][idx] = ++ tot;
p = c[p][idx], len[p] = i + 1;
}
}
queue<int> q;
inline void bfs() {
for (int i = 0; i < 4; ++ i)
if (c[0][i]) q.push(c[0][i]);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < 4; ++ i) {
int v = c[u][i];
if (!v) {c[u][i] = c[fail[u]][i]; continue;}
fail[v] = c[fail[u]][i];
q.push(v);
}
}
}
inline void work() {
int p = 0;
register int i;
for (i = 0; str[i]; ++ i) {
int idx = mean[(int)str[i]];
p = c[p][idx], vis[p] = true;
}
for (i = 1; i <= tot; ++ i) cnt[len[i]] ++;
for (i = 1; i <= tot; ++ i) cnt[i] += cnt[i - 1];
for (i = 1; i <= tot; ++ i) sa[cnt[len[i]] --] = i;
for (i = tot; i; -- i) vis[fail[sa[i]]] |= vis[sa[i]];
}
inline void query(char* ss) {
int p = 0, mx = 0;
for (int i = 0; ss[i]; ++ i) {
int idx = mean[(int)ss[i]];
p = c[p][idx];
if (vis[p]) mx = len[p];
else break;
}
printf("%d\n", mx);
}
int main() {
mean['E'] = 0, mean['S'] = 1, mean['W'] = 2, mean['N'] = 3;
scanf("%d%d", &n, &m);
scanf("%s", str);
for (register int i = 0; i < m; ++ i) {
scanf("%s", s[i]);
insert(s[i]);
}
bfs(), work();
for (register int i = 0; i < m; ++ i) query(s[i]);
}