洛谷 P4569 - [BJWC2011]禁忌(AC 自动机+矩阵乘法)
又好久没做过 AC 自动机的题了,做道练练手罢(
首先考虑对于某个固定的字符串怎样求出它的伤害,我们考虑贪心,每碰到出现一个模式串就将其划分为一段,最终该字符串的代价就是划分的次数。具体来说我们记录一个 \(pre\) 表示上一次在 \(pre\) 与 \(pre-1\) 划分为一段,我们从前往后扫一遍,每扫到一个 \(i\),就检验 \(s[pre...i],s[pre+1...i],s[pre+2...i],\cdots,s[i...i]\) 中是否有子串在模式串中出现过,如果有就令答案加 \(1\),并将 \(pre\) 赋为 \(i\)。正确性显然。
显然这种多模式串的题可以想到 AC 自动机。建出自动机,然后设 \(dp_{i,j}\) 表示已经填好了前 \(i\) 个位置上的字符,当前匹配到了 \(j\) 号节点的概率,转移显然可以枚举 \(j\) 的子节点 \(k\),\(dp_{i+1,k}\leftarrow dp_{i,j}\times\dfrac{1}{\text{alpha}}\),那么怎么体现”划分完的部分就不考虑了“呢?很简单,如果 \(k\) 是匹配节点,那我们就令 \(dp_{i+1,\text{root}}\leftarrow dp_{i,j}\times\dfrac{1}{\text{alpha}}\) instead of \(dp_{i+1,k}\leftarrow dp_{i,j}\times\dfrac{1}{\text{alpha}}\),并且由于期望的线性性,这边答案产生了 \(1\) 的贡献,故还需令 \(ans\leftarrow dp_{i,j}\times\dfrac{1}{\text{alpha}}\)。
由于这题 \(len\) 数据范围很大,故可以套路地想到矩阵快速幂。建立转移矩阵,快速幂转移即可。时间复杂度 \((\sum|s|)\log len\)。还有一个小问题,就是这个 \(ans\) 如何一边求 \(dp\) 的值一遍维护。我们考虑令矩阵的大小扩大 \(1\),即一般的矩阵快速幂我们是 \(\begin{bmatrix}dp_{i,1}\\dp_{i,2}\\\cdots\\dp_{i,m}\end{bmatrix}\) 转移到 \(\begin{bmatrix}dp_{i+1,1}\\dp_{i+1,2}\\\cdots\\dp_{i+1,m}\end{bmatrix}\),而这题我们考虑增加一行 \(ans\),即从 \(\begin{bmatrix}dp_{i,1}\\dp_{i,2}\\\cdots\\dp_{i,m}\\ans\end{bmatrix}\) 转移到 \(\begin{bmatrix}dp_{i+1,1}\\dp_{i+1,2}\\\cdots\\dp_{i+1,m}\\ans\end{bmatrix}\)。具体来说对于一个点 \(j\),如果它的儿子中有 \(c\) 个匹配点,那么我们就令 \(ans\leftarrow ans+dp_{i,j}\times\dfrac{c}{\text{alpha}}\),这个也可在转移矩阵中表示出来。
最后再多说一句,如果你矩阵乘法是使用矩阵乘向量,也就是矩阵在前,向量在后的写法,要将转移到的位置设作行号,从哪个位置转移设为列号,我因为这地方写反了调了好久……xtbz
typedef long double ld;
const int MAXL=75;
const int ALPHA=26;
int n,len,alpha;char buf[MAXL+5];
int ch[MAXL+5][ALPHA+2],fail[MAXL+5],ncnt=0;
bool ed[MAXL+5];
void insert(char *s){
int len=strlen(s+1),cur=0;
for(int i=1;i<=len;i++){
if(!ch[cur][s[i]-'a']) ch[cur][s[i]-'a']=++ncnt;
cur=ch[cur][s[i]-'a'];
} ed[cur]=1;
}
void getfail(){
queue<int> q;
for(int i=0;i<alpha;i++) if(ch[0][i]) q.push(ch[0][i]);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<alpha;i++){
if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]);
else ch[x][i]=ch[fail[x]][i];
}
}
}
struct mat{
ld a[MAXL+5][MAXL+5];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat res;
for(int i=0;i<=ncnt;i++) for(int j=0;j<=ncnt;j++)
for(int k=0;k<=ncnt;k++) res.a[i][j]+=a[i][k]*rhs.a[k][j];
return res;
}
};
int main(){
scanf("%d%d%d",&n,&len,&alpha);
for(int i=1;i<=n;i++) scanf("%s",buf+1),insert(buf);
getfail();mat trs,mul,tt;
for(int i=0;i<=ncnt;i++) for(int j=0;j<alpha;j++){
if(ed[ch[i][j]]) trs.a[0][i]+=1.0/alpha,trs.a[ncnt+1][i]+=1.0/alpha;
else trs.a[ch[i][j]][i]+=1.0/alpha;
} ncnt++;trs.a[ncnt][ncnt]=1;
for(int i=0;i<=ncnt;i++) mul.a[i][i]=1;
for(;len;len>>=1,trs=trs*trs) if(len&1) mul=mul*trs;
tt.a[0][0]=1;tt=mul*tt;printf("%.10Lf\n",tt.a[ncnt][0]);
return 0;
}
洛谷 P4569 - [BJWC2011]禁忌(AC 自动机+矩阵乘法)的更多相关文章
- bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法
题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=2553 题解: 利用AC自动机的dp求出所有的转移 然后将所有的转移储存到矩阵中,进行矩阵 ...
- 【bzoj1444】[Jsoi2009]有趣的游戏 AC自动机+矩阵乘法
题目描述 输入 注意 是0<=P 输出 样例输入 样例输出 题解 AC自动机+矩阵乘法 先将所有字符串放到AC自动机中,求出Trie图. 然后构建邻接矩阵:如果x不是某个字符串的末位置,则x连向 ...
- BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵
原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...
- [BJOI2011]禁忌 --- AC自动机 + 矩阵优化 + 期望
bzoj 2553 [BJOI2011]禁忌 题目描述: Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平.而后,Koishi ...
- 洛谷-P5357-【模板】AC自动机(二次加强版)
题目传送门 -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题 sol:AC自动机,还是要解决跳fail边产生的重复访问,但 ...
- 洛谷P3966 [TJOI2013]单词(AC自动机)
题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出格式 输入格式: 第一行一个整数N,表 ...
- 洛谷P3966 单词 [TJOI2013] AC自动机
正解:AC自动机 解题报告: 传送门! 先来提供一个40pts错解QAQ 首先看到这题就会想到AC自动机板子题2鸭!然后就照着那题的套路打一下,随便改一点儿,简单来说就是每次经过一个节点都要++,然后 ...
- 洛谷P2444 病毒 [POI2000] AC自动机
正解:AC自动机 解题报告: 传送门! 首先看到这种题目二话不说先把trie树和fail指针建立起来 然后就想鸭,如果我们想让模式串和文本串尽量不能匹配,就要想办法让它跳fail指针,而不是继续往下走 ...
- 洛谷P2444 病毒【AC自动机】
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
随机推荐
- 初学Python “登录”案例 更新!!
更新内容:添加了登录次数,如果超过限制的次数,则提示账户被锁定,去某邮箱申请解锁账户! 此次仅把登录系统更新之后源代码放到这里,不在共享源文件在网盘了! 1 ''' 2 登录界面 3 ''' 4 5 ...
- 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链
散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...
- OO第三次博客作业--第三单元总结
一.JML 语言的理论基础及应用工具链 JML 是一种行为接口规格语言,提供了对方法和类型的规格定义手段.通过 JML 和其支持工具,不仅可以基于规格自动构造测试用例,并整合了 SMT Solver ...
- Noip模拟66 2021.10.2
T1 接力比赛 思路就是直接做背包$dp$,然后看看容量相同的相加的最大值. 考虑如何在$dp$过程中进行优化 注意到转移方程的第二维枚举容量没有必要从容量总和开始枚举 那么我们便转移边统计前缀和,从 ...
- mybatis竟然报"Invalid value for getInt()"
目录 背景 场景 初探 再探 结局 背景 使用mybatis遇到一个非常奇葩的问题,错误如下: Cause: org.apache.ibatis.executor.result.ResultMapEx ...
- Oracle ORA 12541 报错解决过程
Oracle 导入全库之后使用plsql登陆时报错 版本12C版本2 ORA-12541: TNS: No Listener 再oracle主机本地可以使用sqlplus 登陆,但是使用plsql无法 ...
- BugKu之备份是个好习惯
题目:备份是个好习惯 思路分析 打开题目,看到一个字符串. 联系到题目,就猜到肯定是源代码泄露,用工具扫一下,发现了index.php.bak,验证了我的猜想,下载下来看看. <?php /** ...
- geoserver控制服务访问权限-类似百度地图的key
目录 缘起 可行性分析 如何实现key验证访问 如何控制key能访问哪些地图服务? 如何实现服务器ip白名单 流程梳理 申请key 访问地图 实施步骤 拦截器设置 配置key验证规则 配置服务拦截规则 ...
- Springboot 启动分析
启动类 Spring 启动类主要是 Annotation (@SpringBootApplication) 和 main 方法体中的 SpringApplication.run. 其中注解 @Spri ...
- MySQL基础语句(MySQL内置函数 )
MySQL 字符串函数 函数 描述 实例 ASCII(s) 返回字符串 s 的第一个字符的 ASCII 码. 返回 CustomerName 字段第一个字母的 ASCII 码: SELECT ASCI ...