BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)
诶这题洛谷居然没有???
题目链接: 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、矩阵乘法)的更多相关文章
- BZOJ 1444: [Jsoi2009]有趣的游戏 AC自动机+概率与期望+矩阵乘法
这道题还比较友好~首先,构建出来 $AC$ 自动机,那么我们要求的就是从 $0$ 号点走无限次走到一个终止节点的概率. 考虑构建转移矩阵 $M,$ $M_{i,j}$ 表示节点 $i$ 转移到节点 $ ...
- BZOJ 1444 [Jsoi2009]有趣的游戏 (AC自动机 + 概率DP + Gauss)
1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1382 Solved: 498[Submit][Statu ...
- BZOJ 1444: [Jsoi2009]有趣的游戏 [AC自动机 高斯消元]
1444: [Jsoi2009]有趣的游戏 题意:每种字母出现概率\(p_i\),有一些长度len的字符串,求他们出现的概率 套路DP的话,\(f[i][j]\) i个字符走到节点j的概率,建出转移矩 ...
- 【BZOJ1444】[Jsoi2009]有趣的游戏 AC自动机+概率DP+矩阵乘法
[BZOJ1444][Jsoi2009]有趣的游戏 Description Input 注意 是0<=P Output Sample Input Sample Output HINT 30%的 ...
- BZOJ1444[Jsoi2009]有趣的游戏——AC自动机+概率DP+矩阵乘法
题目描述 输入 注意 是0<=P, n , l, m≤ 10. 输出 样例输入 input 1 3 2 2 1 2 1 2 AB BA AA input 2 3 4 2 1 2 1 2 AABA ...
- BZOJ 1444:[JSOI2009]有趣的游戏
BZOJ 1444:[JSOI2009]有趣的游戏 题目链接 首先我们建出Trie图,然后高斯消元. 我们设\(f_i\)表示经过第\(i\)个点的期望次数: \[ f_x=\sum i\cdot p ...
- BZOJ:4820: [Sdoi2017]硬币游戏&&BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)
1444: [Jsoi2009]有趣的游戏 4820: [Sdoi2017]硬币游戏 这两道题都是关于不断随机生成字符后求出现给定字符串的概率的问题. 第一题数据范围较小,将串建成AC自动机以后,以A ...
- bzoj 1444: [Jsoi2009]有趣的游戏【AC自动机+dp+高斯消元】
https://blog.sengxian.com/solutions/bzoj-1444 orz 一直是我想错了,建出AC自动机之后,实际上这个定义是设f[i]为经过i节点的 * 期望次数 * ,因 ...
- ●BZOJ 1444 [Jsoi2009]有趣的游戏
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1444题解.1: 概率dp,矩阵乘法,快速幂. 对所有串建立AC自动机, 那么如果在trie树 ...
随机推荐
- mysql创建用户,并授予权限
mysql> GRANT ALL PRIVILEGES ON *.* TO jiqing@"%" IDENTIFIED BY '123456'; Query OK, 0 ro ...
- 神经网络结构设计指导原则——输入层:神经元个数=feature维度 输出层:神经元个数=分类类别数,默认只用一个隐层 如果用多个隐层,则每个隐层的神经元数目都一样
神经网络结构设计指导原则 原文 http://blog.csdn.net/ybdesire/article/details/52821185 下面这个神经网络结构设计指导原则是Andrew N ...
- 在PL/SQL使用游标获取数据及动态SQL
1.游标概念: 当在PL/SQL块中执行DML(增删改)时,Oracle会为其分配上下文区(Context Area),游标是指向上下文区的指针 2. 游标分类: A. 隐式游标 a. 在PL/ ...
- E20170928-hm
deploy vt. (尤指军事行动) 使展开; 施展; 有效地利用;部署 bate vt. 减轻; 压制; 减去; 使软化; vi. <方> 减少; 减弱 ...
- poj Code(组合数)
Code Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 9918 Accepted: 4749 Description ...
- [Swift通天遁地]九、拔剑吧-(9)创建支持缩放、移动、裁切的相机视图控制器
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- js将字符串中所有反斜杠\替换成正斜杠/
区分正斜杠与反斜杠: 正斜杠:http://.http紧跟着的斜杠,离手输入最近的斜杠,shift中间斜杠.45度角斜杠.正斜杠不需要转义 反斜杠:回车与空格之间.程序表示时需要转义成\\. str. ...
- Android App签名(为apk签名)
最近有朋友问到 android 签名的问题,所以转一篇给大家分享: 这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用. 1.签名的意义 为了保证每个应用程序开 ...
- day02_12/12/2016_bean的实例化之构造器方式
- SVN异常处理(五)-状态小图标不见了
1.发现问题 装了Win10,再装了Office2016等一些最新软件后,发现SVN状态小图标竟然就不见了 2.分析问题 在Window系统中,当UAC启动时,有些应用程序的图标上会显示一个盾牌,像这 ...