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);
}
原文地址:https://www.cnblogs.com/huangchenyan/p/10486189.html