诶这题洛谷居然没有???

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1444

题解: 我见到主要有两种做法。

一是矩阵乘法。设\(dp[t][i]\)表示时间\(t\)之后在AC自动机\(i\)节点的概率,那么转移是一个矩阵乘法的形式,构造转移矩阵\(f\), 如果\(u\)是某个串的结尾点,则\(f[u][u]=1,f[u][v]=0 (v\ne u)\), 否则直接按概率搞。

然后这个矩阵的\(t\)次幂就可以得到\(t\)时刻后在每个点的概率。但是这题时间到无穷。

可以感觉到随着\(t\)的增加不匹配任何串的概率不断减小,\(t\)无穷大时达到0. 而题目精度要求并不高,所以如果我们能够使得\(t\)非常大而精度误差被控制在要求范围内,就做完了。

非常粗略地估算一下,\(t=10^{12}\)时矩阵每一项的精度误差远小于\(1\times 10^{-4}\) (别问我怎么算的,我放缩的幅度太大了,实际的界应该小于\(10^{12}\))

所以把矩阵自乘\(40\)次就完了。时间复杂度\(O(n^6\times 40)\) (所有范围为\(10\)的参数不加以区分)

二是高斯消元。

对于任何节点\(u\), 其概率等于所有入边的概率乘上其字母权值之和,然后这样可以列出\(siz\) (AC自动机大小)个方程,但是如果这么解的话得到的答案是所有未知数全等于\(0\), 然后就把根的方程去掉,改成所有结束节点的概率之和等于\(1\), 解出来就A掉了……

完全不理解他是要干什么,拿某些题解代码一看,发现有的点解出来概率都是\(2\)……

到最后终于翻到一篇详细解释这个做法的题解: 如果设概率直接拿方程列上会全得\(0\), 原来这个未知数设的并非概率,而是经过该点的期望次数(对于结束节点期望次数就等于概率),然后\(x_0\) (\(0\)为根)等于所有入边概率之和\(+1\) (因为上来先到一次), 其余节点等于所有入边概率之和即可解。也可以不要根的那个等式,换成所有结束节点期望次数之和为\(1\), 应该是等价的。(天哪看了一晚上终于看懂了……)

时间复杂度\(O(n^6)\)

据说还有一个枚举每个人的\(O(n^7)\)做法……大佬们太强了我啥都看不懂啊

三是矩阵求逆,这个貌似(对我来说)还好理解一些……

矩阵第\(i\)行第\(j\)列是从\(i\)转移到\(j\)的概率,结尾节点的这一行全部为0. 这个和做法一的区别就是结尾节点转移到自己的概率不是\(1\), 那么原来要求\(T^{+\inf}\)现在就变成要求\(T+T^2+T^3+...+T^{+\inf}\), 这个矩阵元素都小于\(1\)应该收敛的,那么直接求\(T\times (1-T)^{-1}\)即可。

时间复杂度\(O(n^6)\)

代码

做法一

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;const int N = 10;
const int S = 10;
const int LEN = 10;
const int SIZ = 100;
const int LGM = 40;
int son[SIZ+3][S+3];
int fail[SIZ+3];
int que[SIZ+3];
double p[N+3];
int id[N+3];
char a[N+3][LEN+3];
int n,len,s,siz;struct Matrix
{double a[SIZ+3][SIZ+3];Matrix operator *(const Matrix &arg) const{Matrix ret;for(int i=0; i<=siz; i++) for(int j=0; j<=siz; j++) ret.a[i][j] = 0.0;for(int i=0; i<=siz; i++){for(int k=0; k<=siz; k++){for(int j=0; j<=siz; j++){ret.a[i][j] += a[i][k]*arg.a[k][j];}}}return ret;}
} f;void insertstr(char str[],int sid)
{int u = 0;for(int i=1; i<=len; i++){if(son[u][str[i]]==0) {siz++; son[u][str[i]] = siz;}u = son[u][str[i]];}id[sid] = u;
}void buildACA()
{int head = 1,tail = 0;for(int i=1; i<=s; i++){if(son[0][i]) {tail++; que[tail] = son[0][i];}fail[son[0][i]] = 0;}while(head<=tail){int u = que[head]; head++;for(int i=1; i<=s; i++){if(son[u][i]) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = son[u][i];}else {son[u][i] = son[fail[u]][i];}}}
}int main()
{scanf("%d%d%d",&n,&len,&s);for(int i=1; i<=s; i++){double x,y; scanf("%lf%lf",&x,&y); p[i] = x/y;}for(int i=1; i<=n; i++){scanf("%s",a[i]+1); for(int j=1; j<=len; j++) a[i][j]-=64;insertstr(a[i],i);}buildACA();for(int u=0; u<=siz; u++){for(int i=1; i<=s; i++){int v = son[u][i];f.a[u][v] += p[i];}}for(int i=1; i<=n; i++){int u = id[i];for(int j=0; j<=siz; j++) f.a[u][j] = (u==j) ? 1.0 : 0.0;}for(int i=1; i<=LGM; i++){f = f*f;}for(int i=1; i<=n; i++) printf("%.2lf\n",f.a[0][id[i]]);return 0;
}

BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)相关推荐

  1. BZOJ 1444: [Jsoi2009]有趣的游戏 [AC自动机 高斯消元]

    1444: [Jsoi2009]有趣的游戏 题意:每种字母出现概率\(p_i\),有一些长度len的字符串,求他们出现的概率 套路DP的话,\(f[i][j]\) i个字符走到节点j的概率,建出转移矩 ...

  2. BZOJ 1444: [Jsoi2009]有趣的游戏

    1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1114  Solved: 386 [Submit][Sta ...

  3. BZOJ:4820: [Sdoi2017]硬币游戏BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)

    1444: [Jsoi2009]有趣的游戏 4820: [Sdoi2017]硬币游戏 这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题. 第一题数据范围较小,将串建成AC自动机以后,以A ...

  4. 【bzoj1444】[Jsoi2009]有趣的游戏 AC自动机+矩阵乘法

    题目描述 输入 注意 是0<=P 输出 样例输入 样例输出 题解 AC自动机+矩阵乘法 先将所有字符串放到AC自动机中,求出Trie图. 然后构建邻接矩阵:如果x不是某个字符串的末位置,则x连向 ...

  5. BZOJ 1444 [JSOI2009]有趣的游戏 (Trie图/AC自动机+矩阵求逆)

    题目大意:给你$N$个长度相等且互不相同的模式串,现在有一个字符串生成器会不断生成字符,其中每个字符出现的概率是$p_{i}/q_{i}$,当生成器生成的字符串包含了某个模式串,则拥有该模式串的玩家胜 ...

  6. [BZOJ1444]有趣的游戏(AC自动机+矩阵乘法)

    n个等长字符串,机器会随机输出一个字符串(每个字母出现的概率为p[i]),问每个字符串第一个出现的概率是多少. 显然建出AC自动机,套路地f[i][j]表示i时刻位于节点j的概率. 构建转移矩阵,当i ...

  7. bzoj 1030: [JSOI2007]文本生成器(AC自动机+DP)

    1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 5187  Solved: 2136 [Submit][St ...

  8. bzoj 2553 [BeiJing2011]禁忌——AC自动机+概率DP+矩阵

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2553 看了题解才会-- 首先,给定一个串,最好的划分方式是按禁忌串出现的右端点排序,遇到能填 ...

  9. AC自动机 + 概率dp + 高斯消元 --- HDU 5955 or 2016年沈阳icpc H [AC自动机 + 概率dp + 高斯消元]详解

    题目链接 题目大意: 就是有NNN个人,每个人都会猜一个长度为LLL的只包含{1,2,3,4,5,6}\{1,2,3,4,5,6\}{1,2,3,4,5,6}的序列,现在裁判开始投掷骰子,并且把每次的 ...

最新文章

  1. 如果不发论文,我们用什么证明自己的科研实力?
  2. 北京尚学堂|程序员励志名言
  3. LeetCode Algorithm 559. N 叉树的最大深度
  4. Hibernate 关系映射
  5. equals()方法
  6. 布尔运算_3dmax教程 - 布尔运算
  7. 已读服务器返回为空,钉钉考勤显示已读什么意思
  8. java中的scanner用法
  9. 政府信息化与电子政务
  10. 企业微信api接口,企业微信sdk
  11. (研究向)如何使用Windows任务管理器看BadApple
  12. 小米手机助手linux,小米手机助手
  13. 华创e路航固件_华创e路航地图官方版
  14. 计算机网络中期论文,计算机 毕业论文(设计)中期报告
  15. 竹子的精神高山流水,赞美竹子的句子,竹子散文
  16. AWS Credentials
  17. 内网禁用u盘 远程协助_如何在Windows 10中禁用远程协助
  18. 离散数学笔记(期末复习用,持续更新…)
  19. 转载——MinMax算法详解
  20. python networkx 边权重_networkx(Python)中基于边权重排序的相邻边

热门文章

  1. 吴恩达《Machine Learning》精炼笔记 1:监督学习与非监督学习
  2. 3DSlicer25:Report an Error
  3. [Medical Image Process] 3.2 GrayScale Morphology(灰阶图像形态学及基本运算)
  4. delphi中move函数的用法
  5. 如果已经知道某一CALL的具体作用,能否把后面所有相同的CALL都改成函数名形式?
  6. asp.net session 介绍一三种Session存储方式
  7. python向数据库插入数据时报错%d format: a number is required, not str
  8. stm32 输入捕获学习(二)
  9. DM8168_ETV_V1.1开发板mount主机常见问题
  10. 图论—割点zcmu2095