P2292 [HNOI2004]L语言

传送门

DP+字典树

设 如果存在一种分法,使得第 i 个字符能被理解,并且 i 为此分法中的最后一个字符

(显然也是最后一个单词的最后一个字符)

那么 f [ i ] = 1

那么就是要求最大的 i 使得 f [ i ] = 1

考虑如何转移

如果知道了 f [ i ] = 1

那么 f[ i+len ] = 1 (从i+1~len的串刚好可以与字典树中的一个单词匹配)

然后就可以转移了:

对于每一个f [ i ] =1,以 i+1 为起点,在字典树上一路匹配下去

如果匹配到当前的字符是一个单词的结尾,就更新 f 数组

实现看代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int s[2000007],len;
inline void read_s()
{
    char ch=getchar(); len=0;
    while(ch<'a'||ch>'z') ch=getchar();
    while(ch>='a'&&ch<='z') s[++len]=ch-'a',ch=getchar();
}//快读
char a[17];
int ch[1007][37],cnt;//字典树
int n,m,ans;
bool p[1007],f[2000007];//p为字典树中的结束标记
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",a);
        int u=0,l=strlen(a);
        for(int j=0;j<l;j++)
        {
            int v=a[j]-'a';
            if(!ch[u][v]) ch[u][v]=++cnt;
            u=ch[u][v];
            if(j==l-1) p[u]=1;
            //建立字典树
        }
    }
    while(m--)
    {
        read_s();
        memset(f,0,sizeof(f));
        f[0]=1; ans=0;
        for(int i=0;i<=len;i++)
        {
            if(!f[i]) continue;
            for(int k=1,j=ch[0][s[i+k]]; j; k++,j=ch[j][s[i+k]])
                if(p[j]) f[i+k]=1;
            //状态转移
            }
        //for(int i=0;i<=len;i++)
            //cout<<f[i]<<" ";
        //cout<<endl;
        for(int i=len;i;i--)
            if(f[i])
            {
                ans=i;
                break;
            }
        cout<<ans<<endl;
    }
}

其实暴力搜索可过..

关于搜索的解法:传送门

posted @ 2018-09-13 17:25  LLTYYC  阅读(203)  评论(0编辑  收藏  举报