1283. 玄武密码
题目链接
1283. 玄武密码
在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河。
相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中。
老人们说,这是玄武神灵将天书藏匿在此。
很多年后,人们终于在进香河地区发现了带有玄武密码的文字。
更加神奇的是,这份带有玄武密码的文字,与玄武湖南岸台城的结构有微妙的关联。
于是,漫长的破译工作开始了。
经过分析,我们可以用东南西北四个方向来描述台城城砖的摆放,不妨用一个长度为 \(N\) 的序列来描述,序列中的元素分别是 E,S,W,N
,代表了东南西北四向,我们称之为母串。
而神秘的玄武密码是由四象的图案描述而成的 \(M\) 段文字。
这里的四象,分别是东之青龙,西之白虎,南之朱雀,北之玄武,对东南西北四向相对应。
现在,考古工作者遇到了一个难题。
对于每一段文字,其前缀在母串上的最大匹配长度是多少呢?
输入格式
第一行有两个整数,\(N\) 和 \(M\),分别表示母串的长度和文字段的个数;
第二行是一个长度为 \(N\) 的字符串,所有字符都满足是 E,S,W,N
中的一个;
之后 \(M\) 行,每行有一个字符串,描述了一段带有玄武密码的文字。依然满足,所有字符都满足是 E,S,W,N
中的一个。
输出格式
输出有 \(M\) 行,对应 \(M\) 段文字。
每一行输出一个数,表示这一段文字的前缀与母串的最大匹配串长度。
数据范围
\(1≤N≤10^7,\)
\(1≤M≤10^5,\)
保证每一段文字的长度均小于等于 \(100\)。
输入样例:
7 3
SNNSSNS
NNSS
NNN
WSEE
输出样例:
4
2
0
解题思路
后缀自动机
后缀自动机裸题,由于后缀自动机形成的有向无环图恰好能够保存所有不同的子串,即从源点出发,沿任意一些字符能够到达的状态节点形成的子串在原字符串中都存在,故对于有每一个匹配串,都可以直接沿着后缀自动机形成的有向无环图走一遍,当无路可走或走完所有匹配串字符时即找到最长的前缀长度
- 时间复杂度:\(O(n+100m)\)
代码
// Problem: 玄武密码
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/1285/
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e7+5;
int n,m,cnt=1,lst=1;
char s[N];
struct Node
{
int fa,len;
int ch[4];
}node[N<<1];
inline int get(char c)
{
if(c=='E')return 0;
if(c=='S')return 1;
if(c=='N')return 2;
return 3;
}
void extend(int c)
{
int p=lst,np=lst=++cnt;
node[np].len=node[p].len+1;
for(;p&&!node[p].ch[c];p=node[p].fa)node[p].ch[c]=np;
if(!p)node[np].fa=1;
else
{
int q=node[p].ch[c];
if(node[q].len==node[p].len+1)node[np].fa=q;
else
{
int nq=++cnt;
node[nq]=node[q];
node[nq].len=node[p].len+1;
node[q].fa=node[np].fa=nq;
for(;p&&node[p].ch[c]==q;p=node[p].fa)node[p].ch[c]=nq;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s);
for(int i=0;s[i];i++)extend(get(s[i]));
while(m--)
{
scanf("%s",s);
int p=1,res=0;
for(int i=0;s[i];i++)
{
int c=get(s[i]);
if(!node[p].ch[c])break;
p=node[p].ch[c];
res++;
}
printf("%d\n",res);
}
return 0;
}