当前位置:网站首页>P5231 [JSOI2012]玄武密码(SAM 经典运用)
P5231 [JSOI2012]玄武密码(SAM 经典运用)
2022-07-31 09:35:00 【Morgannr】
[JSOI2012]玄武密码
题目背景
在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河。相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中。老人们说,这是玄武神灵将天书藏匿在此。
很多年后,人们终于在进香河地区发现了带有玄武密码的文字。更加神奇的是,这份带有玄武密码的文字,与玄武湖南岸台城的结构有微妙的关联。于是,漫长的破译工作开始了。
题目描述
经过分析,我们可以用东南西北四个方向来描述台城城砖的摆放,不妨用一个长度为 n n n 的序列 s s s 来描述,序列中的元素分别是 E
,S
,W
,N
,代表了东南西北四向,我们称之为母串。而神秘的玄武密码是由四象的图案描述而成的 m m m 段文字。这里的四象,分别是东之青龙,西之白虎,南之朱雀,北之玄武,对东南西北四向相对应。
现在,考古工作者遇到了一个难题。对于每一段文字 t t t,求出其最长的前缀 p p p,满足 p p p 是 s s s 的子串。
输入格式
第一行有两个整数,分别表示母串的长度 n n n 和文字段的个数 m m m。
第二行有一个长度为 n n n 的字符串,表示母串 s s s。
接下来 m m m 行,每行一个字符串,表示一段带有玄武密码的文字 t t t。
输出格式
对于每段文字,输出一行一个整数,表示最长的 p p p 的长度。
样例 #1
样例输入 #1
7 3
SNNSSNS
NNSS
NNN
WSEE
样例输出 #1
4
2
0
提示
数据规模与约定
- 对于 20 % 20\% 20% 的数据,保证 n ≤ 100 n \leq 100 n≤100, m ≤ 50 m \leq 50 m≤50。
- 对于 40 % 40\% 40% 的数据,保证 n ≤ 2 × 1 0 4 n \leq 2 \times 10^4 n≤2×104, m ≤ 2 × 1 0 3 m \leq 2 \times 10^3 m≤2×103。
- 对于 70 % 70\% 70% 的数据,保证 n ≤ 1 0 6 n \leq 10^6 n≤106, m ≤ 2 × 1 0 4 m \leq 2 \times 10^4 m≤2×104。
- 对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 1 0 7 1 \leq n \leq 10^7 1≤n≤107, 1 ≤ m ≤ 1 0 5 1 \leq m \leq 10^5 1≤m≤105, 1 ≤ ∣ t ∣ ≤ 100 1 \leq |t| \leq 100 1≤∣t∣≤100, s , t s, t s,t 中均只含字母
E
S
W
N
。
思路:
由于后缀自动机形成的有向无环图恰好能够保存所有不同的子串,即从源点出发,沿任意一些字符能够到达的状态节点形成的子串在原字符串中都存在,故对于有每一个匹配串,都可以直接沿着后缀自动机形成的有向无环图走一遍,当无路可走或走完所有匹配串字符时即找到最长的前缀长度
代码:
#include <bits/stdc++.h>
using namespace std;
//#define int long long
const int N = 1e7 + 10, M = N << 1;
int fa[M], ch[M][5], len[M];
int tot = 1, np = 1;
int n, m;
char s[N], ss[110];
int hah[26];
void extend(int c) {
int p = np;
np = ++tot;
len[np] = len[p] + 1;
while (p && !ch[p][c]) {
ch[p][c] = np;
p = fa[p];
}
if (!p) {
fa[np] = 1;
}
else {
int q = ch[p][c];
if (len[q] == len[p] + 1) {
fa[np] = q;
}
else {
int nq = ++tot;
len[nq] = len[p] + 1;
fa[nq] = fa[q], fa[q] = fa[np] = nq;
while (p && ch[p][c] == q) {
ch[p][c] = nq;
p = fa[p];
}
memcpy(ch[nq], ch[q], sizeof ch[q]);
}
}
}
signed main()
{
hah['E' - 'A'] = 0, hah['S' - 'A'] = 1, hah['W' - 'A'] = 2, hah['N' - 'A'] = 3;
scanf("%d%d", &n, &m);
scanf("%s", s);
for (int i = 0; s[i]; ++i) {
extend(hah[s[i] - 'A']);
}
while (m--) {
scanf("%s", ss);
int nod = 1, cnt = 0;
for (int i = 0; ss[i]; ++i) {
if (!ch[nod][hah[ss[i] - 'A']]) {
break;
}
nod = ch[nod][hah[ss[i] - 'A']];
++cnt;
}
printf("%d\n", cnt);
}
return 0;
}
边栏推荐
猜你喜欢
随机推荐
vue element form表单规则校验 点击提交后直接报数据库错误,没有显示错误信息
(C语言基础)原样输入输出
Browser usage ratio js radar chart
如何在 TiDB Cloud 上使用 Databricks 进行数据分析 | TiDB Cloud 使用指南
MySQL----多表查询
loadrunner脚本--添加事务
js department budget and expenditure radar chart
Kotlin—基本语法(一)
【Redis高手修炼之路】Jedis——Jedis的基本使用
5.for in 和 for of区别和使用
win10镜像下载
自定义v-drag指令(横向拖拽滚动)
Pytorch学习记录(七):自定义模型 & Auto-Encoders
02 Truffle TutorialToken 示例
【Excel】生成随机数字/字符
Splunk Workflow action 给我们带来的好处
loadrunner-Controller负载测试-各模块功能记录01测试场景设计
canvas粒子变幻各种形状js特效
【TCP/IP】网络模型
生成随机数