【bzoj1212】【HNOI2004】L语言

题目描述

标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。

一段文章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下能够被理解的最长前缀的位置。


输入

输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。之后的n行每行描述一个单词,再之后的m行每行描述一段文章。

其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1M。


输出

对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置。


样例输入

4 3 
is
name
what
your
whatisyourname
whatisyouname
whaisyourname


样例输出

14
6
0

 



题解

trie+dp。dp[ i ] 表示位置 i 之前的前缀能不能被理解,那么 dp[ i ] = 1的条件为 存在 j ≤ i && dp[ j ] =1 && s[ j ] 到 s [ i ] 能被理解。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=1000+50;

int n,m,t[maxn][30],len,tot,root;
char c[1000000+50];
bool word[maxn],dp[1000000+50];

void insert(){
    len=strlen(c+1);
    root=0;int id;
    for(int i=1;i<=len;i++){
        id=c[i]-'a';
        if(!t[root][id]) t[root][id]=++tot;
        root=t[root][id];
    }
    word[root]=true;
}

void find(){
    len=strlen(c+1);
    memset(dp,0,sizeof(dp));
    dp[0]=1;
    root=0;int id;
    for(int i=0;i<len;i++){
        if(dp[i]){
            int j=i+1;
            root=t[0][c[j]-'a'];
            while(root&&j<=len){
                if(word[root]) dp[j]=1;
                root=t[root][c[++j]-'a'];
            }
        }
    }
    for(int i=len;i>=1;i--){
        if(dp[i]){
            printf("%d\n",i); return ;
        }
    }
    printf("0\n");
}

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

int main(){
    memset(word,false,sizeof(word));
    read(n),read(m);
    for(int i=1;i<=n;i++){
        cin>>c+1;
        insert();
    }
    while(m--){
        cin>>c+1;
        find();
    }
    return 0;
}

 

posted @ 2018-10-13 09:25  rld  阅读(149)  评论(0编辑  收藏  举报