题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=1212
做法
首先看到多个单词匹配就直接想到AC自动机了啊,然后把AC自动机建出来,做匹配的时候有点不同,以f[i]表示以i结尾的前缀能否匹配,然后我是在每个单词的结尾挂了个vector,表示这个节点结尾的单词长度,用fin[i][j]表示。
那么我们每走到一个节点,把fail指针都遍历一遍,然后对于这些节点,f[i]|=f[i-fin[i][j]],表示我在i-fin[i][j]最后插入我现在这个单词,如果i-fin[i][j]可以匹配,那么i就可以匹配了。
最后从后往前找到第一个f值为1的数输出就好了。
代码
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#define LL long long
#define N (1000005)
using namespace std;
int n,m;
template <typename T> void read(T&t) {
t=0;
bool fl=true;
char p=getchar();
while (!isdigit(p)) {
if (p=='-') fl=false;
p=getchar();
}
do {
(t*=10)+=p-48;p=getchar();
}while (isdigit(p));
if (!fl) t=-t;
}
struct node{
int len,h,t,now,cnt;
int fail[305],ch[305][26],fali[305],q[N];
bool f[N];
char c[N];
vector <int> fin[N];
void insert(){
scanf("%s",c+1);
len=strlen(c+1);
now=0;
for (int i=1;i<=len;i++){
int tt=c[i]-'a';
if (!ch[now][tt]) ch[now][tt]=++cnt;
now=ch[now][tt];
}
fin[now].push_back(len);
}
void get(){
h=t=0;
for (int i=0;i<26;i++){
if (ch[0][i]) q[++t]=ch[0][i];
}
while (h<t){
int u=q[++h],y;
for (int i=0;i<26;i++){
if (y=ch[u][i]){
fail[y]=ch[fail[u]][i],q[++t]=y;
}
else ch[u][i]=ch[fail[u]][i];
}
}
}
void solve(){
scanf("%s",c+1);
int len=strlen(c+1),now=0;
memset(f,0,sizeof(f));
f[0]=1;
for (int i=1;i<=len;i++){
now=ch[now][c[i]-'a'];
for (int t=now;t;t=fail[t]){
for (int j=0;j<fin[t].size();j++){
if (f[i-fin[t][j]]){
f[i]=1;
break;
}
}
}
}
for (int i=len;i>=0;i--){
if (f[i]){
printf("%d\n",i);
return;
}
}
}
}Tree;
int main(){
read(n),read(m);
for (int i=1;i<=n;i++) Tree.insert();
Tree.get();
for (int i=1;i<=m;i++){
Tree.solve();
}
return 0;
}