>Link
ybtoj前缀匹配
luogu P5231
>解题思路
其实也是AC自动机的模板稍微改下就行了
根据母串寻找时,对走过的节点进行标记,最后求答案时再根据
n
n
n个子串在
T
r
i
e
Trie
Trie树上走一遍,找到每个子串路径上被标记过的最大深度
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 10000010
using namespace std;
queue<int> Q;
int n, m, t[N][5], cnt, p, nxt[5 * N], ans;
string s, a[N];
bool mark[N * 5];
int change (char x)
{
if (x == 'E') return 1;
if (x == 'S') return 2;
if (x == 'W') return 3;
return 4;
}
void build_trie ()
{
for (int i = 1; i <= m; i++)
{
cin >> a[i];
int len = a[i].size();
p = 0;
for (int j = 0; j < len; j++)
{
int x = change (a[i][j]);
if (!t[p][x]) t[p][x] = ++cnt;
p = t[p][x];
}
}
}
void get_fail ()
{
for (int i = 1; i <= 4; i++)
{
if (!t[0][i]) continue;
Q.push (t[0][i]);
nxt[t[0][i]] = 0;
}
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = 1; i <= 4; i++)
{
if (!t[u][i]) t[u][i] = t[nxt[u]][i];
else
{
Q.push(t[u][i]);
nxt[t[u][i]] = t[nxt[u]][i];
}
}
}
}
void ACauto ()
{
p = 0;
for (int i = 0; i < n; i++)
{
int x = change (s[i]);
p = t[p][x];
int v = p;
while (v && !mark[v])
{
mark[v] = 1;
v = nxt[v];
}
}
}
int main()
{
scanf ("%d%d", &n, &m);
cin >> s;
build_trie ();
get_fail ();
ACauto ();
for (int i = 1; i <= m; i++)
{
int len = a[i].size();
p = ans = 0;
for (int j = 0; j < len; j++)
{
int x = change (a[i][j]);
p = t[p][x];
if (mark[p]) ans = max (ans, j + 1);
}
printf ("%d\n", ans);
}
return 0;
}