【BZOJ1030】[JSOI2007] 文本生成器(AC自动机上跑DP)
大致题意: 给你\(N\)个字符串(只含大写字母),要你求出有多少个由\(M\)个大写字母构成的字符串含有这\(N\)个字符串中的至少一个。
\(AC\)自动机
看到题目,应该比较容易想到用\(AC\)自动机去做。
但是,即使用了\(AC\)自动机,这题直接求还是很麻烦,所以我们需要将题意先转化一下。
题意转化
考虑对于一个由\(M\)个大写字母构成的字符串,无非有两种情况:
- 第一种情况: 这个字符串中含有这\(N\)个字符串中的至少一个。
- 第二种情况: 这个字符串中不含这\(N\)个字符串中的任意一个。
题目中让我们求的是第一种情况的方案数,但是,第二种情况的方案数显然更好搞。
因此,我们只需求出第二种情况的方案数,再用总方案数\(26^M\)减去它,就是第一种情况的方案数了。
那么第二种情况的方案数怎么求呢?就需要用上\(DP\)了。
动态规划
考虑用\(f_{i,j}\)来表示一共由\(i\)个大写字母构成,最后到达\(Trie\)上第\(j\)个节点的字符串中不含\(N\)个字符串中任意一个字符串的方案数。
初始化时,对于每一个不为这\(N\)个字符串中任意一个字符串的结尾的节点\(i\),\(f_{0,i}=1\)
那么状态转移方程应为:
\]
最后,\(f_{m,rt}\)即为第二种情况的方案数。
因此,最后答案就是\(26^M-f_{m,rt}\),至于\(26^M\)要不要用快速幂来优化,那随你便吧(反正我是写了)。
写的过程中还有一些小细节可以优化,这里就不多说了,直接上代码吧。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=ch:(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=ch))
#define M 100
#define SUM 6000
#define MOD 10007
int pp_;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
int n,m,f[M+5][SUM+5];//f[i][j]表示一共由i个大写字母构成,最后到达Trie上第j个节点的字符串中不含n个字符串中任意一个字符串的方案数
namespace AC_Automation//AC自动机
{
int rt=1,tot=1;
struct Trie
{
int Son[26],Next,Cnt;
}node[SUM+5];
queue<int> q;
inline void Insert(string st)//将一个字符串st插入Trie中
{
register int i,nxt,x=rt,len=st.length();
for(i=0;i<len;++i)
{
if(!node[x].Son[nxt=st[i]-65]) node[x].Son[nxt]=++tot;
x=node[x].Son[nxt];
}
++node[x].Cnt;//统计这一个节点是否有字符串
}
inline void GetNext()//求失配指针
{
register int i,k;q.push(rt);
while(!q.empty())
{
k=q.front(),q.pop();
for(i=0;i<26;++i)
{
if(k^rt)
{
if(!node[k].Son[i]) node[k].Son[i]=node[node[k].Next].Son[i];
else node[node[k].Son[i]].Next=node[node[k].Next].Son[i],node[node[k].Son[i]].Cnt|=node[node[node[k].Son[i]].Next].Cnt,q.push(node[k].Son[i]);
}
else
{
if(!node[k].Son[i]) node[k].Son[i]=rt;
else node[node[k].Son[i]].Next=rt,q.push(node[k].Son[i]);
}
}
}
}
inline int GetAns()//求答案
{
register int i,j,k;
for(GetNext(),i=1;i<=tot;++i)
if(!node[i].Cnt) f[0][i]=1;//初始化每个不是n个字符串中某一字符串结尾的节点f[0][i]=1
for(i=1;i<=m;++i)//DP的核心代码
for(j=1;j<=tot;++j)
for(k=0;k<26;++k)//枚举第j个节点的每一个儿子
if(!node[j].Cnt) (f[i][j]+=f[i-1][node[j].Son[k]])%=MOD;//若i不是n个字符串中某一字符串结尾的节点,则计算f[i][j]
register int res=1,x=26,p=m;//快速幂(写不写无所谓,写了也比O(m)求快不了多少)
while(p)
{
if(p&1) (res*=x)%=MOD;
(x*=x)%=MOD,p>>=1;
}
return ((res-f[m][rt])%MOD+MOD)%MOD;//两数相减后可能为负,因此要加上一个MOD
}
};
inline void read(int &x)
{
x=0;static char ch;
while(!isdigit(ch=tc()));
while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
}
inline void read_string(string &x)
{
x="";static char ch;
while(isspace(ch=tc()));
while(x+=ch,!isspace(ch=tc())) if(!(~ch)) return;
}
inline void write(int x)
{
if(x>9) write(x/10);
pc(x%10+'0');
}
int main()
{
register int i,j;register string ss;
for(read(n),read(m),i=1;i<=n;++i) read_string(ss),AC_Automation::Insert(ss);//将n个字符串插入Trie中
return write(AC_Automation::GetAns()),fwrite(pp,1,pp_,stdout),0;//输出答案
}
【BZOJ1030】[JSOI2007] 文本生成器(AC自动机上跑DP)的更多相关文章
- BZOJ1030[JSOI2007]文本生成器——AC自动机+DP
题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固 ...
- [Bzoj1030][JSOI2007]文本生成器(AC自动机&dp)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1030 最最最常见的多串匹配问题!题目求至少包含一个子串的方案数,则可以转化成全部方案-不 ...
- BZOJ1030 [JSOI2007]文本生成器 AC自动机 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1030 题意概括 给出n个模式串,问长度为m的串中有多少个至少含有这n个模式串中的任意一个. 注意, ...
- [bzoj1030][JSOI2007]文本生成器——AC自动机
Brief Description 给定一些模式串,您需要求出满足以下要求的字符串的个数. 长度为m 包含任意一个模式串 Algorithm Design 以下内容来自神犇博客 首先运用补集转换,转而 ...
- [BZOJ1030] [JSOI2007] 文本生成器 (AC自动机 & dp)
Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是 ...
- BZOJ1030: [JSOI2007]文本生成器(AC自动机)
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 5984 Solved: 2523[Submit][Status][Discuss] Descripti ...
- [BZOJ1030]:[JSOI2007]文本生成器(AC自动机+DP)
题目传送门 题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群, 他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是 ...
- BZOJ 1030 文本生成器 | 在AC自动机上跑DP
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1030 题解: 鸽 #include<cstdio> #include<al ...
- bzoj1030: [JSOI2007]文本生成器(AC自动机+DP)
第一次写这类题...懵 直接计算答案不好计算,所以补集转化求不合法的方案. 首先考虑朴素的DP,设$f(i, s)$表示前$i$个字符,字符串为$s$的方案数,且任意一个给定串都不存在$s$中. 我们 ...
随机推荐
- [Xcode 实际操作]三、视图控制器-(6)UINavigationController导航栏样式
目录:[Swift]Xcode实际操作 本文将演示对导航栏进行样式设置,以及更改导航顶部的提示区. 选择编辑第一个视图控制器文件. import UIKit class FirstSubViewCon ...
- ldap第一天 编译安装LDAP + ldapadmin
此文整理学习此大神的博客:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26168435&id=5746284 一.环 ...
- python模块之datetime方法详细介绍
datetime Python提供了许多内置模块用于操作时间日期,如calendar,time,datetime,这篇文章主要是对datetime进行汇总,datetime模块的借口实现原则更加直观, ...
- Zipkin — 微服务链路跟踪.
一.Zipkin 介绍 Zipkin 是什么? Zipkin的官方介绍:https://zipkin.apache.org/ Zipkin是一款开源的分布式实时数据追踪系统(Distributed ...
- 《从0到1学习Flink》—— Apache Flink 介绍
前言 Flink 是一种流式计算框架,为什么我会接触到 Flink 呢?因为我目前在负责的是监控平台的告警部分,负责采集到的监控数据会直接往 kafka 里塞,然后告警这边需要从 kafka topi ...
- 基于nginx的FastCGI的缓存配置
废话不多说了, 直接上配置, 其实 fastcgi_cache 和 proxy_cache 的配置基本一样: # !缓存文件存放目录 # levels 缓存层次 # keys_zone 缓存空间名和共 ...
- Dede友情链接和分页列表和内容分页去掉小圆点LI标签
我用了一个比较老式的模板,友情链接和列表页底下的一段分页导航会自动获取LI标签,导致错位.每段文字前还多出一个可恶的黑色实心小圆点,心想肯定是LI标签在搞怪,于是把模板文件和样式文件都翻看了一个底朝天 ...
- 《web-Mail服务的搭建》
首先是搭建后台服务: 下载下面2个软件包 extmail-1.2.tar.gz extman-1.1.tar.gz 创建一个extsuite目录,固定格式 mkdir /var/www/extsuit ...
- 让我们把KBEngine玩坏吧!如何定制我们自己的C++函数(一)
为什么不更新kbe warring的代码解读了,因为在我看来那个demo讲完了实体就没东西可讲了,如果专心的看官方文档和PPT的话demo的代码后面没任何难点了已经,单纯的复制黏贴代码实在太过无聊.程 ...
- concurrent.futures模块与协程
concurrent.futures —Launching parallel tasks concurrent.futures模块同时提供了进程池和线程池,它是将来的使用趋势,同样我们之前学习 ...