• 文本生成器(AC自动机+dp)


    F. 文本生成器
    内存限制:512 MiB 时间限制:1000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较

    题目描述

    原题来自:JSOI 2007

    JSOI 交给队员 ZYX 一个任务,编制一个称之为「文本生成器」的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是 GW 文本生成器 v6 版。该软件可以随机生成一些文章――总是生成一篇长度固定且完全随机的文章——也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章包含单词 ,当且仅当单词 是文章的子串)。

    但是,即使按照这样的标准,使用者现在使用的 GW 文本生成器 v6 版所生成的文章也是几乎完全不可读的。ZYX 需要指出 GW 文本生成器 v6 生成的所有文本中可读文本的数量,以便能够成功获得 v7 更新版。你能帮助他吗?
    输入格式

    输入的第一行包含两个正整数,分别是使用者了解的单词总数N,GW 文本生成器 v6 生成的文本固定长度M;以下N行,每一行包含一个使用者了解的单词。
    输出格式

    一个整数,表示可能的文章总数。只需要知道结果模1e4+7

    的值。
    样例
    样例输出

    2 2
    A
    B

    样例输出

    100

    数据范围与提示

    对于全部数据,N<=60,所有单词及文本的长度不会超过100 ,并且只可能包含英文大写字母。

    析:求合法的方案数,如果直接求那么比较难搞,那么我们就用单步容斥,合法=总数-不合法,而总数很显然为 26^m , 现在问题就变成了求不合法的方案数,那么我们就要在每个单词末尾打一个标记,不合法的就是没有标记的单词,

    Refun:学长说AC自动机的DP都非常套路

    大部分f[i][j]表示当前在节点j,且串长为i时的情况,

    有时再加一维表示这个状态里面包含了哪些东西

    而且AC自动机的DP会经常让你用矩阵乘法优化 
    那么行吧,我们就设 f[i][j] 表示当前长度为 i ,所在节点为 j 的不合法的方案数
    那么 f[i][use[j].son[k]]+=f[i-1][j];
    计算过程中注意取模

    #include<bits/stdc++.h>
    #define re register int
    #define int long long
    using namespace std;
    const int mo=1e4+7;
    int n,m,ans,sum,cnt=1;
    char s[1100];
    int f[210][70*26*20];
    queue<int>q;
    struct CUN
    {
        int fail,flag;
        int son[30];
    }use[70*26*20];
    void insert(char ss[])
    {
        int l=strlen(ss);
        int now=1;
        for(re i=0;i<l;i++)
        {
            int p=ss[i]-'A';
            if(!use[now].son[p])
                use[now].son[p]=++cnt;
            now=use[now].son[p];
        }
        use[now].flag=1;
    }
    void get_fail()
    {
        for(re i=0;i<26;i++)
            use[0].son[i]=1;
        use[1].fail=0;
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();
            int Fail=use[u].fail;
            q.pop();
            for(re i=0;i<26;i++)
            {
                int v=use[u].son[i];
                if(!v)
                {
                    use[u].son[i]=use[Fail].son[i];
                    continue;
                }
                use[v].fail=use[Fail].son[i];
                if(use[use[v].fail].flag)
                    use[v].flag|=use[use[v].fail].flag;
                q.push(v);
            }
        }
    }
    int ksm(int d,int z)
    {
        int out=1;
        while(z)
        {
            if(z&1)
                out=out*d%mo;
            z>>=1;
            d=d*d%mo;
        }
        return out;
    }
    signed main()
    {   
        cin>>n>>m;
         for(re i=1;i<=n;i++)
         {
             cin>>s;
             insert(s);
         }
         get_fail();
        f[0][1]=1;
         for(re i=1;i<=m;i++)
         {
             for(re j=1;j<=cnt;j++)
             {
                 for(re k=0;k<26;k++)
                 {
                     if(!use[use[j].son[k]].flag)
                     {
                         f[i][use[j].son[k]]=(f[i][use[j].son[k]]%mo+f[i-1][j]%mo)%mo;
                     }
                 }
             }
         }
         ans=ksm(26,m);
         for(re i=1;i<=cnt;i++)
            ans=(ans-f[m][i]+mo)%mo;
        printf("%lld\n",(ans%mo+mo)%mo);
    }
    
  • 相关阅读:
    fdfs上传图片成功在浏览器中访问不到404 Not Found
    G1 GC日志:Application time: 0.8766273 seconds
    nginx编译问题:make[1]: *** [/usr/local/pcre//Makefile] Error 127
    Datatable报错Uncaught TypeError: Cannot read property 'cell' of undefined
    信息: Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level
    [HDU1176]免费馅饼(DP)
    [程序员代码面试指南]二叉树问题-找到二叉树中的最大搜索二叉树(树形dp)
    [程序员代码面试指南]二叉树问题-在二叉树中找到累加和为指定值的最长路径长度
    [程序员代码面试指南]数组和矩阵-求最短通路值(BFS)
    [程序员代码面试指南]9-判断点在三角形内
  • 原文地址:https://www.cnblogs.com/WindZR/p/14880262.html
Copyright © 2020-2023  润新知