• BZOJ1030: [JSOI2007]文本生成器


    1030: [JSOI2007]文本生成器

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 5544  Solved: 2301
    [Submit][Status][Discuss]

    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

    HINT

    Source

    【题解】

    至今不能掌握AC自动机上DP的神奇状态。。。

    直接考虑包含的不好考虑,考虑不包含的,即限制了AC自动机上一些点不能走

    考虑一个文本串在AC自动机上做匹配,要求匹配失败的串的个数ans,用26^m - ans即可

    令dp[i][j]表示长度为i的串,匹配到j,串的方案数

    可以肯定同一个串一定在同一个位置结束

    按照正常匹配的方法转移,对于走到k,有dp[i+1][k] += dp[i][j],必须要求以k为结尾的这条链不包含某一个字符串

    可以确定只要dp[i][j]有值,说明k之前的链不包含,加入k之后可能包含,也就是说即使包含,也是以k为结尾的这条链的后缀

    只需要沿着k一直走fail,看看有没有哪个节点打了tag标记即可

    这里按照蓝书的方法,给tag标记递推了一下,即在建AC自动机的时候,用fail[u]的tag去更新u的tag,这样就不用跳了,减小常数

    ans = Σdp[m][i], i为自动机节点编号

    被手残卡

    以及别忘了pow(26,m) - ans可能小于0

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 #include <queue>
      7 #include <vector>
      8 #include <cmath> 
      9 #define min(a, b) ((a) < (b) ? (a) : (b))
     10 #define max(a, b) ((a) > (b) ? (a) : (b))
     11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
     12 inline void swap(long long &a, long long &b)
     13 {
     14     long long tmp = a;a = b;b = tmp;
     15 }
     16 inline void read(long long &x)
     17 {
     18     x = 0;char ch = getchar(), c = ch;
     19     while(ch < '0' || ch > '9') c = ch, ch = getchar();
     20     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
     21     if(c == '-') x = -x;
     22 }
     23 
     24 const long long INF = 0x3f3f3f3f;
     25 const long long MOD = 10007;
     26 
     27 long long n,m,fail[7000],tag[7000],ch[7000][30],cnt,dp[110][7000];
     28 char s[70][110];
     29 void insert(long long x)
     30 {
     31     long long now = 0;
     32     for(long long i = 1;s[x][i] != '';++ i)
     33     {
     34         long long &tmp = ch[now][s[x][i] - 'A' + 1];
     35         if(tmp) now = tmp;
     36         else now = tmp = ++ cnt;
     37     }
     38     ++ tag[now];
     39 }
     40 long long q[7000], he, ta;
     41 void build()
     42 {
     43     he = ta = 0;
     44     for(register long long i = 1;i <= 26;++ i)
     45         if(ch[0][i]) q[ta ++] = ch[0][i];
     46     while(he < ta)
     47     {
     48         long long now = q[he ++];
     49         for(long long i = 1;i <= 26;++ i)
     50         {
     51             long long u = ch[now][i];
     52             if(!u)    continue;
     53             q[ta ++] = u;
     54             long long v = fail[now];
     55             while(v && !ch[v][i]) v = fail[v];
     56             fail[u] = ch[v][i];
     57             tag[u] |= tag[fail[u]];
     58         }
     59     }
     60 }
     61 void DP()
     62 {
     63     for(long long i = 0;i < m;++ i)
     64         for(long long j = 0;j <= cnt;++j)
     65         {
     66             if(!dp[i][j] || tag[j]) continue;
     67             for(long long c = 1;c <= 26;++ c)
     68             {
     69                 long long k = j;
     70                 while(k && !ch[k][c]) k = fail[k];
     71                 k = ch[k][c];
     72                 if(tag[k]) continue;
     73                 dp[i + 1][k] += dp[i][j];
     74                 if(dp[i + 1][k] >= MOD) dp[i + 1][k] -= MOD;
     75             }
     76         }
     77 }
     78 long long pow(long long a, long long b)
     79 {
     80     long long r = 1, base = a % MOD;
     81     for(;b;b >>= 1)
     82     {
     83         if(b & 1) r *= base, r %= MOD;
     84         base *= base, base %= MOD;
     85     }
     86     return r;
     87 } 
     88 int main()
     89 {
     90     read(n), read(m);
     91     for(long long i = 1;i <= n;++ i) scanf("%s", s[i] + 1), insert(i);
     92     build();dp[0][0] = 1;
     93     DP();
     94     long long sum = 0;
     95     for(register long long i = 0;i <= cnt;++ i) 
     96     {
     97         sum += dp[m][i];
     98         if(sum >= MOD) sum -= MOD;
     99     }
    100     printf("%lld", ((pow(26, m) - sum) % MOD + MOD) % MOD);
    101     return 0;
    102 }
    BZOJ1030
  • 相关阅读:
    [ArcGIS API for JavaScript 4.8] Sample Code-Get Started-MapView,SceneView简介
    [C语言]易错知识点、小知识点复习(1)
    OpenID Connect Core 1.0(二)ID Token
    轻量ORM-SqlRepoEx 重大升级
    OpenID Connect Core 1.0(一)介绍
    轻量ORM-SqlRepoEx (五) 存储过程操作
    轻量ORM-SqlRepoEx (四)INSERT、UPDATE、DELETE 语句
    轻量ORM-SqlRepoEx (三)Select语句
    轻量ORM-SqlRepoEx (二)初始化SqlRepoEx
    轻量ORM-SqlRepoEx (一)SqlRepoEx介绍
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8324905.html
Copyright © 2020-2023  润新知