zoukankan      html  css  js  c++  java
  • BZOJ1030: [JSOI2007]文本生成器

    Description

      JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的?。ZYX需要指出GW文本生成器 v6生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?

    Input

      输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固定长度M;以下N行,每一行包含一个使用者了解的单词。这里所有单词及文本的长度不会超过100,并且只可能包含英文大写字母A..Z

    Output

      一个整数,表示可能的文章总数。只需要知道结果模10007的值。

    Sample Input

    2 2
    A
    B

    Sample Output

    100
     
     
    考虑用总方案数-不合法方案数
    
    用f[i][j]表示长度为i位于Tire树中j号节点时所有不合法的方案数。
    若当前处于j号节点,且Next[j][k]不是一个字符串的结尾,那么就可以由j号节点向Next[j][k]转移,即f[i][Next[j][k]]=f[i][Next[j][k]]+f[i-1][j]
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int p=10007;
    const int N=150;
    const int M=1e4+50;
    int n,m;
    char s[N];
    struct acmach
    {
        int Next[M][26],Fail[M],End[M],f[N][M];
        int root,L;
        int newnode()
        {
            for (int i=0;i<26;i++) Next[L][i]=-1;
            End[L]=0;
            return L++;
        }
        void init()
        {
            L=0;
            root=newnode();
        }
        void Insert(char s[])
        {
    
            int len=strlen(s);
            int now=root;
            for (int i=0;i<len;i++)
            {
                if (Next[now][s[i]-'A']==-1)
                    Next[now][s[i]-'A']=newnode();
                now=Next[now][s[i]-'A'];
            }
            End[now]++;
        }
        void build()
        {
            queue<int>q;
            Fail[root]=root;    //当前节点now的失败指针指向的地方
            for (int i=0;i<26;i++)
            if (Next[root][i]==-1) Next[root][i]=root; //下一个字母为i+'a'的节点的下标为Next[now][i]
            else
            {
                Fail[Next[root][i]]=root;
                q.push(Next[root][i]);
            }
            while (!q.empty())
            {
                int now=q.front(); q.pop();
                for (int i=0;i<26;i++)
                if (Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i]; //指向当前节点fail指针的这个子节点
                else
                {
                    Fail[Next[now][i]]=Next[Fail[now]][i]; //这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
                    q.push(Next[now][i]);
                }
                End[now]+=End[Fail[now]];
            }
        }
        int query()
        {
            f[0][0]=1; //f[i][j]为当前长度为i的字符串处于Trie树中的第j号结点所具有的方案数。
            for (int i=1;i<=m;i++)
            for (int j=0;j<L;j++)
            {
                if (End[j]) continue;
                for (int k=0;k<26;k++)
                {
                    if(End[Next[j][k]]) continue;
                    f[i][Next[j][k]]=(f[i][Next[j][k]]+f[i-1][j])%p;
                }
            }
            int ret=1,sum=0;
            for (int i=1;i<=m;i++) ret=ret*26%p;
            for (int i=0;i<L;i++) sum=(sum+f[m][i])%p;
            return (ret-sum+p)%p;
        }
    }ac;
    int main()
    {
        ac.init();
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%s",s);
            ac.Insert(s);
        }
        ac.build();
        printf("%d
    ",ac.query());
        return 0;
    }
    /*
    2 2
    A
    B
    */
    View Code
  • 相关阅读:
    保存windows 10的登录界面壁纸
    Python 从剪贴板中生成二维码
    SpringBoot
    IDEA8条配置
    Nodejs-hexoBlog
    Mybatis-Plus
    Javaweb文件上传
    GIt基本语法
    JS常用部分整合
    javaweb-maven学习总结
  • 原文地址:https://www.cnblogs.com/tetew/p/11262425.html
Copyright © 2011-2022 走看看