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;
}

原文地址:https://www.cnblogs.com/Zinn/p/9325671.html

时间: 2024-11-05 15:47:05

bzoj1030 [JSOI2007]文本生成器——AC自动机+DP的相关文章

[BZOJ1030] [JSOI2007] 文本生成器 (AC自动机 &amp; dp)

Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完全随机的.如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串).但是,即使按照这样的标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全

【BZOJ-1030】文本生成器 AC自动机 + DP

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3253  Solved: 1330[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )

之前一直没调出来T^T...早上刷牙时无意中就想出错在哪里了... 对全部单词建AC自动机, 然后在自动机上跑dp, dp(i, j)表示匹配到了第i个字符, 在自动机上的j结点的方案数, 然后枚举A~Z进行转移. -------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define idx(c) ((c) -

[JSOI2007]文本生成器 (AC自动机+dp)

Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群, 他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文 章—— 也就是说,生成的文章中每个字节都是完全随机的.如果一篇文章中至少包含使用者们了解的一个单词, 那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串).但是,即使按照这样的 标准,使用者现在使用的GW文本生成器v6版所生成的文章也是

【BZOJ1030】[JSOI2007]文本生成器 AC自动机+动态规划

[BZOJ1030][JSOI2007]文本生成器 Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中每个字节都是完全随机的.如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串).但是,即使按照这样的标准

bzoj1030 文本生成器(AC自动机+dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4777  Solved: 1986[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

[JSOI2007]文本生成器 [AC自动机,dp]

时刻要记住正难则反,可以知道总数是 \(26^m\),我们可以减掉不合法的. AC自动机上面dp,不合法的显然就是没有出现任意的一个串,根据rainy的教导 单词 \(b,bce,abcd\) 的 ACAM 然后 \(dp\) 就好了,由于点数不超过 \(n*m \leq 6000\),然后你每一位枚举复杂度是 \(m^2n\) 的 可以通过本题 // powered by c++11 // by Isaunoya #include <bits/stdc++.h> #define rep(i,

【题解】Luogu P4052[JSOI2007]文本生成器 AC自动机

AC自动机上DP f[i][j]表示节点j,串长为i 当一个串的尾节点被标红或其fail指针指向的被标红,都是可读的 用总的减去不可读的即为答案 #include<iostream> #include<cstring> #include<cstdio> #include<queue> #define MOD (10007) #define N (10005) using namespace std; int Son[N][26],End[N],Fail[N]

BZOJ 1030 JSOI 2007 文本生成器 AC自动机+DP

题目大意:给出一些字符串.已知如果文章里出现过这些字符串中的一个,那么就说这个文章是可读的.问长度为l的文章有多少是可读的文章. 思路:直接处理不太好弄, 我们可以统计出来不可读的文章,然后用26^l减去就是可读的文章总数. 将所有的字串建Trie图,然后设f[i][j]为文章的第i个字符Trie图中的第j个节点的时候不可读的文章的数量.转移就很简单了.注意一下取模就行了. CODE: #include <queue> #include <cstdio> #include <