zoukankan      html  css  js  c++  java
  • 洛谷 P2292 [HNOI2004] L语言 解题报告

    P2292 [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)可以被理解的最长前缀的位置。


    这个题我写的是AC自动机+DP

    先拿AC自动机匹配,然后DP求最长前缀。

    (dp[i])代表第(i)位能够作为某个单词的开始

    转移:(dp[i+len0[i]]=1;)
    即若在位置(i)有单词匹配,就搞上去

    事实上人丑常数大,不吸氧居然过不了

    用前向星存匹配可能快一点,我猜。

    dp也没必要每次都把文本串跑完。


    code:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <vector>
    using namespace std;
    const int N=21,M=1048580;
    int n,m,cnt=0;
    char passage[M],word[12],len0[N],dp[M];
    vector <int > g[M];
    struct node
    {
        int fail,son[26],cnt;
    }t[N*10];
    
    void add(int kk)
    {
        scanf("%s",word);
        int len=strlen(word),now=0;
        len0[kk]=len;
        for(int i=0;i<len;i++)
        {
            int k=word[i]-'a';
            if(t[now].son[k]) now=t[now].son[k];
            else {t[now].son[k]=++cnt;now=cnt;}
        }
        t[now].cnt=kk;
    }
    queue <int > q;
    void AC_fail()
    {
        for(int i=0;i<26;i++)
            if(t[0].son[i])
                q.push(t[0].son[i]);
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=0;i<26;i++)
                if(t[now].son[i])
                {
                    t[t[now].son[i]].fail=t[t[now].fail].son[i];
                    q.push(t[now].son[i]);
                }
                else
                    t[now].son[i]=t[t[now].fail].son[i];
        }
    }
    
    void DP(int len)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        int ans=0;
        for(int i=0;i<=len;i++)
        {
            if(dp[i])
            {
                for(int j=0;j<g[i].size();j++)
                    dp[i+len0[g[i][j]]]=1;
                ans=i;
            }
        }
        printf("%d
    ",ans);
    }
    
    void match()
    {
    
        scanf("%s",passage);
        int len=strlen(passage),now=0;
        for(int i=0;i<len;i++)
            g[i].clear();
        for(int i=0;i<len;i++)
        {
            now=t[now].son[passage[i]-'a'];
            for(int j=now;j;j=t[now].fail)
                if(t[j].cnt) g[i+1-len0[t[j].cnt]].push_back(t[j].cnt);
        }
        DP(len);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) add(i);
        AC_fail();
        for(int i=1;i<=m;i++)
            match();
        return 0;
    }
    
    

    2018.5.22

  • 相关阅读:
    Raid卡在Write back 与Write through 时的性能差异
    mysql 的outfile以及infile 语法简单备份恢复表
    @SneakyThrows
    java中的mmap实现--转
    以ATT&CK为例构建网络安全知识图
    横向移动攻击点与识别
    Tomcat开启JMX监控
    mysql serverTimezone
    自增还是UUID?数据库主键的类型选择,为啥不能用uuid做MySQL的主键?
    数据库:查询结果中增加数据库不存在的字段的方法
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9074843.html
Copyright © 2011-2022 走看看