洛谷 P2292 [HNOI2004]L语言(AC自动机,dp)
传送门
解题思路
设dp[i]为先i位能否被理解。
然后在AC自动机上匹配,若 num[j]&&dp[i-cnt[j]] 则 dp[i] 等于 1。(j为不断fail的指针)
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxn=305;
const int maxm=2e6+5;
int tr[maxn][30],dp[maxm],cnt[maxn],tot,num[maxn],fail[maxn],n,m;
string s;
void insert(string s){
int now=0,len=s.length();
for(int i=0;i<len;i++){
int k=s[i]-'a';
if(!tr[now][k]) tr[now][k]=++tot;
now=tr[now][k];
}
cnt[now]=len;
num[now]++;
}
void build(){
queue<int> q;
for(int i=0;i<26;i++){
if(tr[0][i]) q.push(tr[0][i]);
}
while(!q.empty()){
int now=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[now][i]){
fail[tr[now][i]]=tr[fail[now]][i];
q.push(tr[now][i]);
}else{
tr[now][i]=tr[fail[now]][i];
}
}
}
}
int query(string s){
memset(dp,0,sizeof(dp));
dp[0]=1;
int now=0,len=s.length();
for(int i=0;i<len;i++){
now=tr[now][s[i]-'a'];
for(int j=now;j;j=fail[j]){
if(num[j]&&dp[i-cnt[j]+1]){
dp[i+1]=1;
break;
}
}
}
for(int i=len;i>=0;i--){
if(dp[i]) return i;
}
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>s,insert(s);
build();
for(int i=1;i<=m;i++) cin>>s,cout<<query(s)<<endl;
return 0;
}