lg2292[dp+trie树]

链接:lg2292[dp+trie树]

题解

  • dp[i]表示表示前缀i能否匹配,那么转移方程显然是dp[i]=dp[j]&&(j-i能否匹配) (j<=i)
  • 走的方向是唯一的,那么显然可以用Trie树来维护.
  • 但是还有一个问题,我们是往前匹配,然而正常的Trie树上反向走并不好走,解决方法是反向建Trie树
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,x,y) for(register int i=x;i<=y;++i)
    #define repd(i,x,y) for(register int i=x;i>=y;--i)
    #define ll long long
    using namespace std;
    const int N=1e6+7;
    int tr[N][26],end[N],dp[N],cnt,n,m;
    char a[N];
    inline void add(char *str){
    int len=strlen(str)-1,p=0;
    repd(i,len,0){
    int k=str[i]-'a';
    if(!tr[p][k])tr[p][k]=++cnt;
    p=tr[p][k];
    }
    end[p]++;
    }
    inline void query(char *str,int pos){
    int p=0,flag=0;
    repd(i,pos-1,0){
    if(!tr[p][str[i]-'a'])break;
    p=tr[p][str[i]-'a'];if(dp[i]&&end[p])flag=1;
    }
    dp[pos]=flag;
    }
    int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,n){scanf("%s",a);add(a);}
    rep(i,1,m){
    int ans=0;
    scanf("%s",a);
    memset(dp,0,sizeof(dp));
    int len=strlen(a);
    dp[0]=1;
    rep(i,1,len){query(a,i);if(dp[i])ans=max(i,ans);}
    printf("%d\n",ans);
    }
    return 0;
    }