前缀匹配
题目
输入
输出
输出有 MMM 行
每一行输出一个数,表示查询串的前缀与母串的最大匹配串长度、
输入样例
7 3
SNNSSNS
NNSS
NNN
WSEE
输出样例
4
2
0
解题思路
我们先将询问构成ACACAC自动机,然后让母串在上面跑,遍历到的点到rootrootroot形成的字符串一定是母串的子串
nxtnxtnxt到rootrootroot形成的字符串也是母串的子串
那么我们对遍历到的点跳失配指针,并标记rootrootroot所形成的字符串就是母串的子串
最后再拿询问在上面跑,遇到标记的点就更新即可
程序如下
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
int n, m, tot;
char s[10000001], c[100001][101];
queue <int> q;
struct node
{
int son[4], line;
bool use;
}tree[1000001];
int t(char c)
{
if(c == 'E') return 0;
if(c == 'S') return 1;
if(c == 'W') return 2;
if(c == 'N') return 3;
return -1;
}
void e(int o)
{
int len = strlen(c[o]);
int now = 0;
for(int i = 0; i < len; ++i)
{
int tt = t(c[o][i]);
if(!tree[now].son[tt]) tree[now].son[tt] = ++tot;
now = tree[now].son[tt];
}
}
void b()
{
for(int i = 0; i <= 3; ++i)
{
if(tree[0].son[i])
{
q.push(tree[0].son[i]);
tree[tree[0].son[i]].line = 0;
}
}
while(!q.empty())
{
int now = q.front();
q.pop();
for(int i = 0; i <= 3; ++i)
{
if(tree[now].son[i])
{
q.push(tree[now].son[i]);
tree[tree[now].son[i]].line = tree[tree[now].line].son[i];
}
else tree[now].son[i] = tree[tree[now].line].son[i];
}
}
}
void a()
{
int now = 0;
for(int i = 1; i <= n; ++i)
{
int tt = t(s[i]);
int noww = tree[now].son[tt];
while(noww)
{
tree[noww].use = 1;
noww = tree[noww].line;
}
now = tree[now].son[tt];
}
}
int ask(int o)
{
int len = strlen(c[o]);
int now = 0, sum = 0;
for(int i = 0; i < len; ++i)
{
int tt = t(c[o][i]);
now = tree[now].son[tt];
if(tree[now].use) sum = i + 1;
}
return sum;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
{
s[i] = getchar();
while(t(s[i]) == -1) s[i] = getchar();
}
for(int i = 1; i <= m; ++i)
{
scanf("%s",&c[i]);
e(i);
}
b();
a();
for(int i = 1; i <= m; ++i)
printf("%d\n",ask(i));
return 0;
}