• bzoj1030 [JSOI2007]文本生成器


    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

    Hint

    题解:

    题目中应该很好想到ac自动机来解决这道题,这里我们可以换一种思维方式,问知道的文章不好得出

    结果,可以想有多少不认识的文章,就是说,给定的单词一个都不能出现。就是说如果该单词有就认

    识,那么单词都要避开。

    f[i][j]表示到了i这一位,总共m个,即长度,然后,到了j这一个点,可以获得的方案数。

    那么就需要在建立Trie图的时候处理一下。

    看这个垃圾图,x,y,z点,y指向z,z为标记节点,因为z为y的后缀

    所以y包涵z,y也是不和法的,所以y也需要标记为不可到达。

    然后就是转移了,复杂度可以压过。

     1 #include<cstring>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstdio>
     6 #include<queue>
     7 #define mod 10007
     8 using namespace std;
     9 
    10 int n,m,ans=1,res,cnt=1,f[107][6007];
    11 struct Node
    12 {
    13     int c[26],suf;
    14     bool flag;
    15 }trie[6007];
    16 char ch[107];
    17 
    18 void insert()
    19 {
    20     int now=1,len=strlen(ch);
    21     for (int i=0;i<len;i++)
    22     {
    23         if (!trie[now].c[ch[i]-'A']) trie[now].c[ch[i]-'A']=++cnt;
    24         now=trie[now].c[ch[i]-'A'];
    25     }
    26     trie[now].flag=true;
    27 }
    28 void make_AC()
    29 {
    30     for (int i=0;i<26;i++)
    31         trie[0].c[i]=1;
    32     queue<int>q;while(!q.empty()) q.pop();
    33     trie[1].suf=0;
    34     q.push(1);
    35     while(!q.empty())
    36     {
    37         int u=q.front();q.pop();
    38         for (int i=0;i<26;i++)
    39             if (trie[u].c[i])
    40             {
    41                 trie[trie[u].c[i]].suf=trie[trie[u].suf].c[i];
    42                 if (trie[trie[trie[u].c[i]].suf].flag) trie[trie[u].c[i]].flag=true;
    43                 q.push(trie[u].c[i]);
    44             }
    45             else trie[u].c[i]=trie[trie[u].suf].c[i];
    46     }
    47 }
    48 inline void dp(int x)
    49 {
    50     for (int i=1;i<=cnt;i++)
    51     {
    52         if (trie[i].flag||f[x-1][i]==0) continue;
    53         for (int j=0;j<26;j++)
    54             f[x][trie[i].c[j]]=(f[x][trie[i].c[j]]+f[x-1][i])%mod;
    55     }
    56 }
    57 int main()
    58 {
    59     scanf("%d%d",&n,&m);
    60     for (int i=1;i<=n;i++)
    61     {
    62         scanf("%s",ch);
    63         insert();
    64     }
    65     make_AC();
    66     f[0][1]=1;
    67     for (int i=1;i<=m;i++) dp(i);
    68     for (int i=1;i<=m;i++)
    69         ans=(ans*26)%mod;    
    70     for (int i=1;i<=cnt;i++)
    71         if (trie[i].flag==0) res=(res+f[m][i])%mod;
    72     printf("%d
    ",(ans-res+mod)%mod);     
    73 }
  • 相关阅读:
    CGAffineTransform的使用大概:
    CYLTabBarController的简单使用
    Masonry详解
    Swift学习 (四)
    《Advanced Bash-scripting Guide》学习(二):测试脚本调用的参数是否正确
    《Advanced Bash-scripting Guide》学习(一):对一个增强和广义的删除logfile的脚本的理解
    [JSOI2007]字符加密Cipher
    codevs 3160 最长公共子串
    codevs 1500 后缀排序
    浅谈后缀数组
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7732315.html
Copyright © 2020-2023  润新知