DestinHistoire

 

BZOJ-1212 [HNOI2004]L语言(trie+dp)

题目描述

  一段文章 \(T\) 由若干小写字母构成,一个单词 \(W\) 也是由若干小写字母构成,一个字典 \(D\) 是若干个单词的集合。 我们称一段文章 \(T\) 在某个字典 \(D\) 下是可以被理解的,是指如果文章 \(T\) 可以被分成若干部分,且每一个部分都是字典 \(D\) 中的单词。 例如字典 \(D\) 中包括单词 {is,name,what,your},则文章 whatisyourname 是在字典 \(D\) 下可以被理解的。因为它可以分成 \(4\) 个单词:what,is,your,name,且每个单词都属于字典 \(D\),而文章 whatisyouname 在字典 \(D\) 下不能被理解,但可以在字典 D'=D+{you} 下被理解。这段文章的一个前缀 whatis,也可以在字典 \(D\) 下被理解,而且是在字典 \(D\) 下能够被理解的最长的前缀。 给定一个字典 \(D\),判断若干段文章在字典 \(D\) 下是否能够被理解。 并给出其在字典 \(D\) 下能够被理解的最长前缀的位置。

  字典 \(D\) 中有 \(n\) 个单词,且有 \(m\) 段文章需要被处理,其中 \(1\leq n,m\leq 20\),每个单词长度不超过 \(10\),每段文章长度不超过 \(1MB\)

分析

  把 \(n\) 个单词插入 \(\text{trie}\),在每个单词的结尾字符进行标记,设 \(dp[i]\) 为文章的前 \(i\) 个字符能否在 \(\text{trie}\) 中匹配成功,能匹配成功为 \(1\),不能则为 \(0\)。文章在 \(\text{trie}\) 中匹配时,如果某个节点有单词的结尾标记,则更新 \(dp[j]=1\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
char str[N];
int trie[2010][30],ed[2010],tot=1,dp[N];
void insert(char *str)
{
    int p=1;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int ch=str[i]-'a';
        if(trie[p][ch]==0)
            trie[p][ch]=++tot;
        p=trie[p][ch];
    }
    ed[p]++;
}

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str);
        insert(str);
    }
    while(m--)
    {
        scanf("%s",str+1);
        int len=strlen(str+1),ans=0;
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<=len;i++)
        {
            if(dp[i]==1)
            {
                ans=i;
                int p=1;
                for(int j=i+1;j<=len;j++)
                {
                    int ch=str[j]-'a';
                    p=trie[p][ch];
                    if(p==0)
                        break;
                    if(ed[p]!=0)
                        dp[j]=1;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

posted on 2020-11-24 14:15  DestinHistoire  阅读(67)  评论(0)    收藏  举报

导航