来源:BZOJ1212
trie+dp
实际上自己想还是会有一点困难的,所以借鉴了大神的代码
首先建trie就不说了,关键是如何在字典树上进行这个dp
一维,就是现在匹配到i位置能理解的最多的前缀
我们首先将dp[0] = 1;//这个1是一个标记
下面我们开始dp
实际上就是一个不断匹配,不行就向后来的意思。但是,向后的时候注意我们是要标记我们已经匹配好了,这样子我们就不会丢失任何个一种可能的求得最大前缀的情况。
还是很好理解的,但是自己想有点问题。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = (1<<20)+10;
const int ATLN = 26;
int n,m;
int dp[MAXN];
char ch[MAXN];
struct AC_Machine{
int nxt[MAXN][ATLN];
int tot,root;
bool des[MAXN];
void ini(){
memset(nxt,-1,sizeof nxt);
memset(des,false,sizeof des);
root = tot = 0;
}
void insert(char *str){
int now = root;
int len = strlen(str);
for(int i=0;i<len;i++){
int ptr = str[i]-'a';
if(nxt[now][ptr] == -1) nxt[now][ptr] = ++tot;
now = nxt[now][ptr];
}
des[now] = true;
}
int solve(char *str){
int ans = 0;
int now = root;
int len = strlen(str+1);
dp[0] = 1;
for(int i=0;i<=len;i++){
if(dp[i]!=1) continue;
else ans = i;
int now = root;
for(int j=i+1;j<=len;j++){
int ptr = str[j]-'a';
now = nxt[now][ptr];
if(now==-1) break;
if(des[now] == true) dp[j] = 1;
}
}
return ans;
}
}tree;
int main(){
scanf("%d%d",&n,&m);
tree.ini();
for(int i=1;i<=n;i++) {
scanf("%s",ch);
tree.insert(ch);
}
for(int i=1;i<=m;i++){
scanf("%s",ch+1);
int len = strlen(ch)+11;
memset(dp,0,sizeof(int)*len);
printf("%d\n",tree.solve(ch));
}
return 0;
}