zoukankan      html  css  js  c++  java
  • 【BZOJ】1030: [JSOI2007]文本生成器(AC自动机+dp)

    题目

    传送门:QWQ

    传送到洛谷QWQ


    分析

    我一开始也不会做这题的,后来看了很多网上的题解,终于AC了。(我好菜啊)

    主要参考:传送门QWQ


    直接搞非常麻烦,反正我是不会做。于是考虑求反,即求有多少不包含任何单词的数量。最后再用$ {26}^m $减去就ok了。

    于是在$ AC $自动机上搞$ dp $。

    用 $ dp[i][j] $表示前$ i $个字符在$ AC $自动机上位置为$ j $的方案数。

    那么可以得出$ dp[i+1][k]=dp[i+1][k]+dp[i][j] $如果k是合法的儿子。

    所以还要判断一下合法性(合法性 即:不是任何一个单词的end)


    代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N=6010, MOD=10007;
     4 
     5 int son[N][26], fail[N], end[N], newp, rt, q[N];
     6 int dp[1200][6010], n, m;
     7 char s[N];
     8 
     9 int find(int cur,int i)
    10 {
    11     if(!cur) return rt;
    12     if(son[cur][i]) return son[cur][i];
    13     return fail[son[cur][i]]=find(fail[cur],i);
    14 }
    15 
    16 int main()
    17 {
    18     for (int i=0;i<26;i++) son[0][i]=1;
    19     newp=rt=1;
    20     scanf("%d%d",&n,&m);
    21     
    22     //Trie
    23     for(int i=1;i<=n;i++)
    24     {
    25         scanf("%s",s+1);
    26         int cur=rt, l=strlen(s+1);
    27         for(int j=1;j<=l;j++)
    28         {
    29             if(!son[cur][s[j]-'A']) son[cur][s[j]-'A']=++newp;
    30             cur=son[cur][s[j]-'A'];
    31         }
    32         end[cur]=1;
    33     }
    34     
    35     //fail
    36     int l=1,r=1;q[1]=1;
    37     for(;l<=r;l++)
    38     {
    39         for(int i=0;i<26;i++)
    40         if(son[q[l]][i])
    41         {
    42             fail[son[q[l]][i]]=find(fail[q[l]],i);
    43             q[++r]=son[q[l]][i];
    44         }
    45     }
    46     
    47     //dp
    48     dp[1][1]=1; 
    49     for(int i=1;i<=m;i++)
    50     for(int j=1;j<=newp;j++)
    51     {
    52         for(int k=0;k<26;k++)
    53         {
    54             int cur=j, f=0;
    55             while(cur)
    56             {
    57                 if(end[son[cur][k]]) { f=1; break; }
    58                 cur=fail[cur];
    59             }
    60             if(f) continue;    //不能放 
    61             cur=j;
    62             while(!son[cur][k])
    63             {
    64                 cur=fail[cur];  //从j向fail[j]跳直到有k儿子
    65             }
    66             cur=son[cur][k];
    67             dp[i+1][cur]=(dp[i+1][cur]+dp[i][j])%MOD;
    68         }
    69     }
    70     
    71     int anss=1, ans=0;
    72     for (int i=1;i<=m;i++) anss=(anss*26)%MOD;    //转换
    73     for (int i=1;i<=newp;i++)
    74     {
    75         ans=(ans+dp[m+1][i])%MOD;    //最终答案是所有dp[m+1][x]的和
    76     }
    77     
    78     printf("%d
    ",(anss-ans+MOD)%MOD); 
    79     return 0;
    80 }

  • 相关阅读:
    怎样防止应用因获取IDFA被AppStore拒绝
    多校第九场Arithmetic Sequence题解
    Hadoop文件解压缩
    FZU 2087 统计树边【MST相关】
    hdu2647(拓扑排序)
    jsp自己主动编译机制
    AsyncTask的原理和缺点
    C语言之文件操作08——总结
    Android API 文档 离线秒开方法
    在Windows8系统下exe格式会计课件下载播放帮助图解
  • 原文地址:https://www.cnblogs.com/noblex/p/8424762.html
Copyright © 2011-2022 走看看