做法 :AC自动机
。
我们考虑把 \(M\) 个询问子串建成一棵 \(trie\) 树,构建出 \(fail\) 指针,用长串 \(S\) 在 AC自动机
上进行匹配,根据 \(fail\) 指针的定义,可知对于长串 \(S\) 遍历 \(trie\) 树时遍历过的结点以及此结点通过 \(fail\) 指针跳到的结点 \(u\),在 \(trie\) 树上 \(1\) 到 \(u\) 的路径上的字符串一定存在于长串 \(S\) 上,即某个串的前缀 \(1 … u\) 存在于长串 \(S\) 上,故我们可以在结点 \(u\) 上打标记,再重新遍历每个询问字符串在 \(trie\) 树上的结点,拥有标记即可更新答案。
\(Code:\)
#include <bits/stdc++.h>
const int MaxN = 1e7 + 10;
const int MaxM = 1e5 + 10;
const int MaxLM = 1e2 + 10;
using namespace std;
inline int read() {
int cnt = 0, opt = 1;
char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar())
if (ch == '-') opt = 0;
for (; ch >= '0' && ch <= '9'; ch = getchar())
cnt = (cnt << 3) + (cnt << 1) + (ch ^ 48);
return opt ? cnt : -cnt;
}
inline int modify(char s) {
if (s == 'E') return 0;
if (s == 'S') return 1;
if (s == 'W') return 2;
if (s == 'N') return 3;
}
int n, m;
char s[MaxN], s2[MaxM][MaxLM];
int ch[MaxLM * MaxM][4], tot = 1;
int nxt[MaxN], bo[MaxN];
queue <int> que;
inline void insert(int num) {
int len = strlen(s2[num] + 1), u = 1;
for (int i = 1; i <= len; ++ i) {
int str = modify(s2[num][i]);
if (! ch[u][str]) ch[u][str] = ++ tot;
u = ch[u][str];
}
}//把当前字符串插入 trie 树
inline void make_fail() {
for (int i = 0; i <= 3; ++ i)
ch[0][i] = 1;
que.push(1), nxt[1] = 0;
while (que.size()) {
int u = que.front();
que.pop();
for (int i = 0; i <= 3; ++ i) {
if (! ch[u][i]) ch[u][i] = ch[nxt[u]][i];
else {
que.push(ch[u][i]);
int v = nxt[u];
while (v > 1 && ! ch[v][i]) v = nxt[v];
nxt[ch[u][i]] = ch[v][i];
}
}
}
}//构建 fail 指针
inline void s_find() {
int u = 1;
for (int i = 1; i <= n; ++ i) {
int str = modify(s[i]);
u = ch[u][str];
int k = u;
while (k > 1 && ! bo[k]) {//若 k 结点打过标记,则所有 k 的 fail 指针跳到的结点都打过标记,故可以跳过
bo[k] = 1;
k = nxt[k];
}
}
}//把在 Trie 树上与 s 串匹配的位置打上标记
inline int solve(int num) {
int len = strlen(s2[num] + 1), u = 1;
int ans = 0;
for (int i = 1; i <= len; ++ i) {//遍历当前字符串在 trie 树上的每一个结点
int str = modify(s2[num][i]);
u = ch[u][str];
if (bo[u])//存在标记就更新答案
ans = i;
}
return ans;
}//找出前缀最大匹配
int main() {
n = read(), m = read();
scanf("%s", s + 1);
for (int i = 1; i <= m; ++ i) {
scanf("%s", s2[i] + 1);
insert(i);
}
make_fail();
s_find();
for (int i = 1; i <= m; ++ i)
printf("%d\n", solve(i));
return 0;
}