考虑用\(AC\)自动机来解决本题这样的多字符串匹配问题。

要最大化魔法分割后得到的禁忌串数目,最优情况肯定为在一个串中每个禁忌串的右端点进行分割。对应到\(AC\)自动机上,就是匹配到一个禁忌串后,就直接转移到根节点。

若用朴素的\(DP\)解决,发现题目中的\(len\)过大,于是用矩阵快速幂优化。

先构造初始矩阵,\(a_{i,j}\)的值表示当串长为\(1\)时从状态\(i\)转移到状态\(j\)的概率,对这样的一个矩阵进行\(len\)次幂后,所得的含义即为串长为\(len\)时所对应的概率。

同时新增一个状态\(t\)来统计期望,若转移过程中,转移到了一个合法的状态,即匹配上了一个禁忌串,那么就可以把当前概率统计到状态\(t\)上了,最后直接查询根到状态\(t\)即可。

构造矩阵时,分情况讨论。设\(P=\frac{1}{alphabet}\),若一个状态\(x\)可转移到状态\(y\),若状态\(y\)不是禁忌串的终止状态,则\(a_{x,y}\)加上\(P\),否则让\(a_{x,root}\)加上\(P\)和\(a_{x,t}\)加上\(P\)。

具体实现细节看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 110
using namespace std;
typedef long double ld;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,l,alph,tot,root;
ld P;
int trie[maxn][30],fail[maxn];
bool end[maxn];
char s[maxn];
struct matrix
{
ld a[maxn][maxn];
}m,e;
matrix operator *(const matrix &x,const matrix &y)
{
matrix z;
memset(z.a,0,sizeof(z.a));
for(int k=root;k<=tot+1;++k)
for(int i=root;i<=tot+1;++i)
for(int j=root;j<=tot+1;++j)
z.a[i][j]+=x.a[i][k]*y.a[k][j];
return z;
}
matrix qp(matrix x,int y)
{
matrix t=e;
while(y)
{
if(y&1) t=t*x;
x=x*x;
y>>=1;
}
return t;
}
void insert()
{
int len=strlen(s+1),p=root;
for(int i=1;i<=len;++i)
{
int ch=s[i]-'a';
if(!trie[p][ch]) trie[p][ch]=++tot;
p=trie[p][ch];
}
end[p]=true;
}
void build()
{
queue<int> q;
for(int i=0;i<alph;++i)
if(trie[root][i])
q.push(trie[root][i]);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<alph;++i)
{
int y=trie[x][i];
if(y)
{
fail[y]=trie[fail[x]][i];
end[y]|=end[fail[y]],q.push(y);
}
else trie[x][i]=trie[fail[x]][i];
}
}
e.a[tot+1][tot+1]=m.a[tot+1][tot+1]=1;
for(int x=root;x<=tot;++x)
{
e.a[x][x]=1;
for(int ch=0;ch<alph;++ch)
{
int y=trie[x][ch];
if(end[y]) m.a[x][tot+1]+=P,m.a[x][root]+=P;
else m.a[x][y]+=P;
}
}
}
int main()
{
read(n),read(l),read(alph),P=(ld)1.0/(ld)alph;
for(int i=1;i<=n;++i)
scanf("%s",s+1),insert();
build(),m=qp(m,l);
printf("%Lf",m.a[root][tot+1]);
return 0;
}

题解 洛谷 P4569 【[BJWC2011]禁忌】的更多相关文章

  1. 洛谷 P4569 - [BJWC2011]禁忌(AC 自动机+矩阵乘法)

    题面传送门 又好久没做过 AC 自动机的题了,做道练练手罢( 首先考虑对于某个固定的字符串怎样求出它的伤害,我们考虑贪心,每碰到出现一个模式串就将其划分为一段,最终该字符串的代价就是划分的次数.具体来 ...

  2. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  3. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  4. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  5. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  6. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  7. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  8. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  9. 题解 洛谷 P2010 【回文日期】

    By:Soroak 洛谷博客 知识点:模拟+暴力枚举 思路:题目中有提到闰年然后很多人就认为,闰年是需要判断的其实,含有2月29号的回文串,前四位是一个闰年那么我们就可以直接进行暴力枚举 一些小细节: ...

随机推荐

  1. skywalking与pinpoint全链路追踪方案对比

    由于公司目前有200多微服务,微服务之间的调用关系错综复杂,调用关系人工维护基本不可能实现,需要调研一套全链路追踪方案,初步调研之后选取了skywalking和pinpoint进行对比; 选取skyw ...

  2. jQuery实现全选、反选、删除

    <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...

  3. vueX基础知识点笔记

    vuex是专门用来管理vue.js应用程序中状态的一个插件.他的作用是将应用中的所有状态都放在一起, 集中式来管理.需要声明的是,这里所说的状态指的是vue组件中data里面的属性.简单的来说, 它就 ...

  4. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 实现不了是研发的借口? 实现不了,有时候是功能复杂度较高难以实 ...

  5. 解决SELinux阻止Nginx访问服务

    在使用 yum 安装 nginx 后可能会出现配置完成后却无法访问的问题,查看 audit.log 会发现类似于以下的错误信息 出现此问题的原因是 SELinux 基于最小权限原则默认拦截了 Ngin ...

  6. VS2017配置PCL1.9.1 for win10

    安装链接 https://www.jianshu.com/p/463f54c91ab7 1.9.1 安装包下载 官网路径: https://github.com/PointCloudLibrary/p ...

  7. VS2017未能添加对"System.Drawing.dll"的引用

    问题: 解决方法:在程序集中找到System.Drawing.dll然后勾选引用.

  8. Python并发编程——多线程与协程

    Pythpn并发编程--多线程与协程 目录 Pythpn并发编程--多线程与协程 1. 进程与线程 1.1 概念上 1.2 多进程与多线程--同时执行多个任务 2. 并发和并行 3. Python多线 ...

  9. java 面向对象(三):类结构 属性

    类的设计中,两个重要结构之一:属性 对比:属性 vs 局部变量 1.相同点: * 1.1 定义变量的格式:数据类型 变量名 = 变量值 * 1.2 先声明,后使用 * 1.3 变量都其对应的作用域 2 ...

  10. Django框架07 /cookie和session

    Django框架07 /cookie和session 目录 Django框架07 /cookie和session 1. django请求生命周期 2. cookie 3. session 4. 总结 ...