zoukankan      html  css  js  c++  java
  • BZOJ1030 [JSOI2007]文本生成器 AC自动机 动态规划

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1030


    题意概括

      给出n个模式串,问长度为m的串中有多少个至少含有这n个模式串中的任意一个。

      注意,所有的串仅由A~Z 26个大写字母构成。


    题解

      AC自动机好题。

      先构建一个AC自动机。

      然后在AC自动机上面跑dp。

      建议开滚动数组。

      dp[i][j]表示长度为i,在AC自动机上面走到了j的方案数。

      每次把所有走到模式串尾的全动统计到答案并清零。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N=60+5,L=100+5,Trie_Size=N*L;
    const int mod=10007;
    struct Trie{
        int fail,e;
        int next[26];
        void set(){
            fail=e=0;
            memset(next,0,sizeof next);
        }
    }tree[Trie_Size];
    int cnt;
    void AC_init(){
        cnt=1;
        tree[0].set(),tree[1].set();
        for (int i=0;i<26;i++)
            tree[0].next[i]=1;
    }
    void add(char ch[]){
        int len=strlen(ch),rt=1,t;
        for (int i=0;i<len;i++){
            t=ch[i]-'A';
            if (!tree[rt].next[t]){
                tree[++cnt].set();
                tree[rt].next[t]=cnt;
            }
            rt=tree[rt].next[t];
        }
        tree[rt].e=1;
    }
    void build_AC(){
        int q[Trie_Size],head=0,tail=0,rt,son,k;
        q[++tail]=1,tree[0].fail=1;
        while (head<tail){
            rt=q[++head];
            for (int i=0;i<26;i++){
                son=tree[rt].next[i];
                if (!son){
                    tree[rt].next[i]=tree[tree[rt].fail].next[i];
                    continue;
                }
                k=tree[rt].fail;
                while (!tree[k].next[i])
                    k=tree[k].fail;
                tree[son].fail=tree[k].next[i];
                tree[son].e|=tree[tree[k].next[i]].e;
                q[++tail]=son;
            }
        }
    }
    int n,m,dp[Trie_Size],pre[Trie_Size],Pow[L];
    char str[L];
    int main(){
        scanf("%d%d",&n,&m);
        AC_init();
        for (int i=1;i<=n;i++){
            scanf("%s",&str);
            add(str);
        }
        build_AC();
        Pow[0]=1;
        for (int i=1;i<=m;i++)
            Pow[i]=Pow[i-1]*26%mod;
        memset(dp,0,sizeof dp);
        memset(pre,0,sizeof pre);
        dp[1]=1;
        int ans=0;
        for (int i=1;i<=m;i++){
            for (int j=1;j<=cnt;j++)
                pre[j]=dp[j];
            memset(dp,0,sizeof dp);
            for (int j=1;j<=cnt;j++)
                if (pre[j]>0)
                    for (int k=0;k<26;k++)
                        dp[tree[j].next[k]]=(dp[tree[j].next[k]]+pre[j])%mod;
            for (int j=1;j<=cnt;j++)
                if (tree[j].e){
                    ans=(ans+dp[j]*Pow[m-i])%mod;
                    dp[j]=0;
                }
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    MS Office CVE-2015-1641 恶意 Exploit 样本分析
    Qbot回归,已感染5.4万台计算机
    工具推荐:Backdoor-apk,安卓APK文件后门测试工具
    安卓微信、QQ自带浏览器 UXSS 漏洞
    延迟注入工具(python)
    小白欢乐多——记ssctf的几道题目
    使用转义防御XSS
    富文本存储型XSS的模糊测试之道
    k8s故障总结
    CentOS7.6部署k8s环境
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1030.html
Copyright © 2011-2022 走看看