zoukankan      html  css  js  c++  java
  • [HNOI2004]L语言

    #1212. [HNOI2004]L语言

    Online Judge:Bzoj-1212,Luogu-2292

    Label:Trie,Dp

    题目描述

    Luogu原题链接

    大致题意:

    给定一个含有n个单词的字典,现在一共有m个询问,每个询问输入一个字符串,问这个字符串能被理解的最长前缀位置p是多少,最长前缀从1~p构成的字符串必须能被字典中的单词分割。比如一个字典含有单词{"what","is",“your”,“name”},那么对于某询问"isyournamewty"的最长前缀长度为10。

    输入格式

    输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。 之后的n行每行描述一个单词,再之后的m行每行描述一段文章,所有字符都是小写字母。 其中(1<=n, m<=20),每个单词长度不超过10,每段文章长度不超过(10^6)

    输出格式

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

    样例

    输入

    4 3
    is
    name
    what
    your
    
    whatisyourname
    whatisyouname
    whaisyourname
    

    输出

    14
    6
    0	
    

    样例解释

    询问1:整段文章’whatisyourname’都能被理解

    询问2:前缀’whatis’能够被理解

    询问3:没有任何前缀能够被理解


    题解:

    由于文章长度的数据范围达1e6,对于这种大数据的查询考虑使用Trie

    先套Trie模板,把字典中的单词插入Trie中。然后就是对于每个询问的查询操作了。我们发现询问的字符串的长度很大,而且可能的组成方案不止一种,于是一开始决定对于每种方案进行记忆化搜索,然后xjb递归,结果貌似复杂度没问题但是由于常数巨大我也不知道为什么TLE了??

    其实不用递归来递归去。。用一个bool数组来转移状态就可以了。

    定义(ok[i])表示询问的字符串中前i个字符构成的字符串能否由字典中的单词组成。

    那么将普通的Trie查找改一下,如果当前节点是某单词的结尾,那么就把当前遍历到的位置标记ok=1。单词询问的最多运行次数大约为(O(1e6*10))

    代码如下,详见注释↘

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000010;
    int n,m;
    int f[1010][27],tot;
    bool ok[N],is[1010];
    void insert(char *s){
        int p=0;
        for(int i=0;i<strlen(s);++i){
            int x=s[i]-'a';
            if(!f[p][x])f[p][x]=++tot;
            p=f[p][x];
        }
        is[p]=1;//标记是某单词结尾的节点
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            char s[12];scanf("%s",s);
            insert(s);
        }
        while(m--){
            char s[N];scanf("%s",s+1);
            int len=strlen(s+1),ans=0;
            memset(ok,0,sizeof(ok));
            ok[0]=1;//关于ok数组的定义见上面
            for(int i=0;i<=len;i++){
                if(!ok[i])continue;
                ans=i;
                for(int j=i+1,p=0;j<=len;j++){
                    int x=s[j]-'a';
                    p=f[p][x];
                    if(!p)break;
                    if(is[p])ok[j]=1;//可以拼到j这个位置
                }
            }
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    LeetCode 345. Reverse Vowels of a String 题解
    LeetCode 344. Reverse String 题解
    LeetCode 27. Remove Element 题解
    LeetCode 61. Rotate List 题解
    LeetCode 19.Remove Nth Node From End of List 题解
    Android耗电量
    Android 使用adb查看和修改电池信息
    Android AOP AspectJ 插桩
    Flask相关用法
    Monkey日志信息的11种Event percentage
  • 原文地址:https://www.cnblogs.com/Tieechal/p/11227950.html
Copyright © 2011-2022 走看看