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

题意

给你n个串。问有多少长度为m的串使得这n个串至少在其中出现过一次。输出答案膜10007意义下的结果。

(n<=100,每个串的长度<=100)

题解

在AC自动机上跑DP。

用到一个容斥的思想,求至少出现过一次的次数就是,全部可能-一次都没出现的次数。

所以考虑dp,对于一个长度为i的串从i-1转移,i位置上的数必须不是n个串中某个串的结尾。

所以建立AC自动机,在上面跑。一个儿子从父亲转移时必须保证,儿子节点和儿子节点通过fail指针间接到达的点,都不是终止节点。

具体看代码。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 const int mod=10007;
 9 const int N=7000;
10 int n,m,tot,ans;
11 char s[N];
12 int dp[200][N];
13 struct AC{
14     int nxt[30],e,fail;
15 }ac[N];
16 void insert(char s[]){
17 //    cout<<"asfsfsdfsdfs"<<endl;
18     int len=strlen(s);
19     int now=0;
20     for(int i=0;i<len;i++){
21         if(ac[now].nxt[s[i]-‘A‘]==0)ac[now].nxt[s[i]-‘A‘]=++tot;
22         now=ac[now].nxt[s[i]-‘A‘];
23     }
24     ac[now].e=1;
25 }
26 void get_fail(){
27     queue<int>q;
28     for(int i=0;i<=25;i++){
29         if(ac[0].nxt[i]){
30         //    cout<<"sfsd"<<endl;
31             q.push(ac[0].nxt[i]);
32         }
33     }
34     while(!q.empty()){
35
36         int u=q.front();//cout<<u<<endl;
37         q.pop();
38         for(int i=0;i<=25;i++){
39             if(ac[u].nxt[i]){
40                 ac[ac[u].nxt[i]].fail=ac[ac[u].fail].nxt[i];
41                 ac[ac[u].nxt[i]].e|=ac[ac[ac[u].fail].nxt[i]].e;
42                 q.push(ac[u].nxt[i]);
43             }
44             else ac[u].nxt[i]=ac[ac[u].fail].nxt[i];
45         }
46     }
47 }
48 int main(){
49     scanf("%d%d",&n,&m);
50     for(int i=1;i<=n;i++){
51         scanf("%s",s);
52         insert(s);
53     }
54     get_fail();
55     dp[0][0]=1;
56     for(int i=1;i<=m;i++)
57         for(int j=0;j<=tot;j++)
58             for(int x=0;x<=25;x++){
59                 if(ac[ac[j].nxt[x]].e==0)dp[i][ac[j].nxt[x]]=(dp[i][ac[j].nxt[x]]+dp[i-1][j])%mod;
60             }
61     int ans=1;
62     for(int i=1;i<=m;i++){
63         ans*=26;
64         ans%=mod;
65     }
66     for(int i=0;i<=tot;i++){
67         ans-=dp[m][i];
68         ans=(ans+mod)%mod;
69     }
70     printf("%d",ans);
71     return 0;
72 }

原文地址:https://www.cnblogs.com/Xu-daxia/p/9525060.html

时间: 2024-10-03 08:33:35

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

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) -

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 是单词结尾

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

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

[JSOI2007]文本生成器 (AC自动机+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版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

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

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

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

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

[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 <