zoukankan      html  css  js  c++  java
  • bzoj 1030 [JSOI2007]文本生成器

    在AC自动机上做DP

    dp[i][j]表示在字符串里(文章)中第i个位置在自动机中第j个状态的方案数

    当sh[j].son[k]是一个单词的结尾时,则累计答案,此时i右边的字符都可以在A~Z中任意选择,不转移到下一个状态

    若不是单词的结尾,则转移到下一个状态。

    是否是单词的结尾需要注意,并不只是在加到字典树时最后一个位置,还有其他能以fail指针指到这里的状态

    这是因为若当前的状态失配,则可以直接转移的一个单词的结尾,符合题目条件。

    #include <bits/stdc++.h>
    #define ll long long
    #define mod 10007
    using namespace std;
    ll n,m,dp[110][6100],w,ans;
    ll c[200];
    char a[200];
    struct node
    {
        ll son[27],t,fail;
    }sh[6100];
    void build(char a[])
    {
        ll sz,p;
        sz=strlen(a+1);
        p=1;
        for (int i=1;i<=sz;i++)
        {
            ll num;
            num=a[i]-'A';
            if (sh[p].son[num]==0)
            {
                w++;
                sh[p].son[num]=w;
            }
            p=sh[p].son[num];
            if (i==sz)
              sh[p].t=1;
        }
    }
    void build_fail()//广搜求fail
    {
        queue <ll> q;
        q.push(1);
        while (!q.empty())
        {
            ll f;
            f=q.front();
            q.pop();
            if (f!=1)
              sh[f].t=sh[f].t|sh[sh[f].fail].t;//注意
            for (int i=0;i<=25;i++)
            {
                if (sh[f].son[i]==0)
                {
                    if (f==1)
                      sh[f].son[i]=1;
                    else
                      sh[f].son[i]=sh[sh[f].fail].son[i];
                }
                else
                {
                    if (f==1)
                      sh[sh[f].son[i]].fail=1;
                    else
                      sh[sh[f].son[i]].fail=sh[sh[f].fail].son[i];
                    q.push(sh[f].son[i]);
                }
            }
        }
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        w=1;
        for (int i=1;i<=n;i++)
        {
            scanf("%s",a+1);
            build(a);
        }
        dp[0][1]=1;
        build_fail();
        c[0]=1;
        for (int i=1;i<=m+10;i++)
          c[i]=(c[i-1]*26)%mod;
        for (int i=0;i<m;i++)
        {
            for (int j=1;j<=w;j++)
            {
                if (sh[j].t==1)
                  continue;
                for (int k=0;k<=25;k++)
                {
                    if (sh[sh[j].son[k]].t==1)
                    {
                        ans=(ans+dp[i][j]*c[m-i-1])%mod;
                        continue;//注意
                    }
                    dp[i+1][sh[j].son[k]]=(dp[i+1][sh[j].son[k]]+dp[i][j])%mod;//转移
                }
            }
        }
        printf("%lld
    ",ans%mod);
    }
  • 相关阅读:
    轮询算法
    随机算法
    加权随机算法
    平滑加权轮询算法
    预训练模型与Keras.applications.models权重资源地址
    多通道卷积操作解析
    Squeeze-and-Excitation Networks
    实验数据集概况
    Keras-图片预处理
    Keras常用层
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/10486189.html
Copyright © 2011-2022 走看看