• bzoj1030 [JSOI2007]文本生成器——AC自动机+DP


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1030

    求至少有一个单词的文本串不太好求,所以转化成求所有情况减去没有一个单词的文本串;

    没有一个单词的文本串可以用AC自动机+DP求,设 f[i][j] 表示文本串长度为 i ,当前 Trie 树上节点为 j 的方案数;

    则 f[i][j] 可以转到仍然不包含单词的它的儿子的方案数中,同时文本串长度+1;

    所以需要在 getfail 时把单词结尾的属性也转移一下,因为 fail 是单词结尾的话,自己也一定有一个后缀是单词结尾,也就是自己这里也包含单词了;

    最后统计答案就是所有的 f[m][i] 的和,其中 i 可以是 Trie 树上任意一个点。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    int const mod=10007;
    int n,m,f[105][6005],cnt,ans;
    char s[105];
    queue<int>q;
    struct N{int son[30],fail,end;}t[6005];
    void build()
    {
        int l=strlen(s),nw=0;
        for(int i=0;i<l;i++)
        {
            if(!t[nw].son[s[i]-'A'])t[nw].son[s[i]-'A']=++cnt;
            nw=t[nw].son[s[i]-'A'];
        }
        t[nw].end=1;
    }
    void getfail()
    {
        t[0].fail=0;
        for(int i=0;i<26;i++)
            if(t[0].son[i])
            {
                t[t[0].son[i]].fail=0;
                q.push(t[0].son[i]);
            }
        while(q.size())
        {
            int x=q.front(); q.pop();
            for(int i=0;i<26;i++)
            {
                if(t[x].son[i])
                {
                    t[t[x].son[i]].fail=t[t[x].fail].son[i];
    //                t[t[x].son[i]].end|=t[t[t[x].son[i]].fail].end;
                    q.push(t[x].son[i]);
                }
                else t[x].son[i]=t[t[x].fail].son[i];
            }
            if(t[t[x].fail].end)t[x].end=1;
        }    
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            build();
        }
        getfail();
        f[0][0]=1;//!
        for(int i=0;i<m;i++)
            for(int nw=0;nw<=cnt;nw++)
            {
                if(t[nw].end||!f[i][nw])continue;//
                for(int j=0;j<26;j++)
                {
                    int x=t[nw].son[j];
                    (f[i+1][x]+=f[i][nw])%=mod;
                }
            }
        ans=1;
        for(int i=1;i<=m;i++) (ans*=26)%=mod;
        for(int i=0;i<=cnt;i++) 
            if(t[i].end==0)ans=((ans-f[m][i])%mod+mod)%mod; //end=0!
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    处理键盘弹出
    纯手码自动布局
    ios 随机色 宏定义
    linux下自定义pid实现任意数据采集
    http://blog.chinaunix.net/uid-9845710-id-1996675.html snmpd配置
    http://www.360doc.com/content/10/0928/12/11991_57014502.shtml
    pingall脚本
    http://lihuipeng.blog.51cto.com/3064864/643960
    elf 文件
    php中获取周几的方法
  • 原文地址:https://www.cnblogs.com/Zinn/p/9325671.html
Copyright © 2020-2023  润新知