「SDOI2017」硬币游戏
问题分析
首先一个显然的做法就是建出AC自动机,然后高斯消元。但是这样的复杂度是\(O(n^3m^3)\)的。
我们发现其实只需要求AC自动机上\(n\)个状态的概率,而其余的概率是没有用的。我们不妨设\(i\)赢的概率是\(P_i\)。同时,我们令\(P_0\)为没有任何一个人赢的概率。
然后我们考虑从\(P_0\)转移到\(P_i\)。如果我们直接在\(P_0\)后面加上串\(i\)是可以的。这样的概率是\(\frac{1}{2^m}P_0\)。
但是这样有一个问题:
我们从\(P_0\)转移到\(P_i\)的过程中,可能先转移到了\(P_j\)。比如说,我们在\(P_0\)后加了\(k(0 < k < m)\)位就到了\(j\)。这种情况下,串\(i\)长度为\(k\)的前缀就等于串\(j\)长度为\(k\)的后缀。此时就相当于在\(P_j\)后接一个长为\(m-k\)的串到\(P_i\),而这样的概率是\(\frac{1}{2^{m-k}}P_j\)。
可以借助下图加深理解:
所以我们可以得到\(n\)个方程
\]
其中\(substr(i,j,k)\)表示串\(i\)从\(j\)到\(k\)所构成的子串。
然后还有\(\sum\limits_{i=1}^nP_i=1\),这样我们就有\(n+1\)个未知数,\(n+1\)个方程。然后你就稳了。
参考程序
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 310;
int n, m, A[ Maxn ][ Maxn ], Fail[ Maxn ][ Maxn ];
long double Pow[ Maxn ], B[ Maxn ][ Maxn ];
int main() {
scanf( "%d%d", &n, &m );
for( int i = 1; i <= n; ++i ) {
char Ch[ Maxn ];
scanf( "%s", Ch + 1 );
for( int j = 1; j <= m; ++j )
A[ i ][ j ] = ( Ch[ j ] == 'T' ) ? 1 : 0;
}
for( int i = 1; i <= n; ++i ) {
Fail[ i ][ 1 ] = 0;
int t = 0;
for( int j = 1; j < m; ++j ) {
while( t && A[ i ][ t + 1 ] != A[ i ][ j + 1 ] ) t = Fail[ i ][ t ];
if( A[ i ][ t + 1 ] == A[ i ][ j + 1 ] ) ++t;
Fail[ i ][ j + 1 ] = t;
}
}
Pow[ 0 ] = 1;
for( int i = 1; i <= m; ++i )
Pow[ i ] = Pow[ i - 1 ] * 0.5L;
for( int i = 1; i <= n; ++i )
for( int j = 1; j <= n; ++j ) {
B[ i ][ j ] = 0ll;
int t = 0;
for( int k = 1; k <= m; ++k ) {
while( t && A[ i ][ t + 1 ] != A[ j ][ k ] ) t = Fail[ i ][ t ];
if( A[ i ][ t + 1 ] == A[ j ][ k ] ) ++t;
}
if( i == j ) t = Fail[ i ][ t ];//注意不要漏掉这句
while( t ) {
B[ i ][ j ] += Pow[ m - t ];
t = Fail[ i ][ t ];
}
}
for( int i = 1; i <= n; ++i ) {
B[ i ][ 0 ] = -Pow[ m ];
B[ i ][ i ] += 1ll;
}
for( int i = 1; i <= n; ++i ) B[ 0 ][ i ] = 1;
B[ 0 ][ n + 1 ] = 1;
for( int i = 0; i <= n; ++i ) {
if( B[ i ][ i ] == 0ll )
for( int j = i + 1; j <= n; ++j ) {
if( B[ j ][ i ] )
for( int k = 0; k <= n + 1; ++k )
swap( B[ i ][ k ], B[ j ][ k ] );
break;
}
long double t = B[ i ][ i ];
for( int j = 0; j <= n + 1; ++j ) B[ i ][ j ] /= t;
for( int j = 0; j <= n; ++j ) {
if( j == i ) continue;
long double T = B[ j ][ i ];
for( int k = 0; k <= n + 1; ++k )
B[ j ][ k ] -= B[ i ][ k ] * T;
}
}
for( int i = 1; i <= n; ++i )
printf( "%.10Lf\n", B[ i ][ n + 1 ] );
return 0;
}
「SDOI2017」硬币游戏的更多相关文章
- @loj - 2004@ 「SDOI2017」硬币游戏
目录 @description@ @solution@ @accepted code@ @details@ @description@ 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数 ...
- 题解 「SDOI2017」硬币游戏
题目传送门 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利. 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了. 同学们觉得要加强 ...
- 【LOJ 2004】「SDOI2017」硬币游戏
LOJ 2004 100pts 首先我们肯定要建AC自动机的.. 那么这题就肯定是个AC自动机上\(dp\). 所以想想状态. 首先如果我们把状态设成这样行不行: \(dp(i)\)表示匹配到了i节点 ...
- 【LOJ】#2067. 「SDOI2016」硬币游戏
题解 c一样的就是一个独立的游戏 我们对于2和3的指数 sg[i][j] 表示\(c \cdot 2^i \cdot 3^j\)的棋子,只有这个硬币是反面,翻转的硬币是正面的sg值 枚举sg函数所有可 ...
- 「SDOI2017」树点涂色 解题报告
「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...
- LibreOJ 2003. 「SDOI2017」新生舞会 基础01分数规划 最大权匹配
#2003. 「SDOI2017」新生舞会 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- AC日记——「SDOI2017」序列计数 LibreOJ 2002
「SDOI2017」序列计数 思路: 矩阵快速幂: 代码: #include <bits/stdc++.h> using namespace std; #define mod 201704 ...
- 【LOJ】#2269. 「SDOI2017」切树游戏
题解 把所有的数组一开始就FWT好然后再IFWT回去可以减小常数 从13s跑到0.7s-- 可以参照immortalCO的论文,感受一下毒瘤的动态动态DP 就是用数据结构维护线性递推的矩阵的乘积 由于 ...
- loj#2269. 「SDOI2017」切树游戏
还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...
随机推荐
- 学习python基础规则
前面应该是记流水账的方式,毕竟学习的内容不多无法产出什么有效的内容. 这两天从开始下载Python开始学习,一路顺畅冒的问题,直到开始学习python的游戏规则,严格缩进.注释及‘’的使用等感觉还不错 ...
- leecode100热题 HOT 100
# 题名 题解 通过率 难度 出现频率 1 两数之和 46.5% 简单 2 两数相加 35.5% 中等 3 无重复字符的最长子串 31.1% ...
- springboot2整合zookeeper集成curator
步骤: 1- pom.xml <dependency> <groupId>org.apache.curator</groupId> <artifactId&g ...
- 一个页面多图表展示(四个div的方式)
效果如图所示,一个页面四个div,每个div里面展示相应的数据,因为这种效果会有点麻烦,而且不太雅观我就换了一种写法,一个div里面用四个图表,共用一个图例,先放上这个方式的效果图和源码,后期会再发布 ...
- python之SSH远程登录
一.SSH简介 SSH(Secure Shell)属于在传输层上运行的用户层协议,相对于Telnet来说具有更高的安全性. 二.SSH远程连接 SSH远程连接有两种方式,一种是通过用户名和密码直接登录 ...
- php函数之strtr和str_replace的区别
php字符串替换函数 strtr()有两种用法: strtr(string,from,to) 或者strtr(string,array) 首先针对strtr函数第一种方式: 我们看看下面的举例: &l ...
- docker快速入门02——在docker下开启mysql5.6 binlog日志
1.检查容器状态 [root@localhost ~]# docker ps 执行这个命令可以看到所有正在运行当中的容器,如果加上-a参数,就可以看到所有的容器包括停止的. 我们可以看到容器正在运行当 ...
- KVM和Docker的对比
虚拟化技术对比: KVM:全虚拟化,需要模拟各种硬件 docker:严格来说不算是虚拟化技术,只是进程隔离和资源限制 实例启动进程对比: 在kvm虚拟机中执行top命令,看宿主机进程树,根本看不到to ...
- 简单了解TCP/IP与HTTP
这种东西网上资源非常丰富,完全没有必要造轮子,更何况 这也不是你能造的啊,来 上连接 TCP/IP https://www.runoob.com/tcpip/tcpip-intro.html HTTP ...
- Linux 权限和目录更改、移除、更换目录、列出目录内容、使用通配符、移动、重命名
12 chgrp :改变档案.目录所属群组 chgrp -R dirname/filename chown :改变档案/目录拥有者 chown -R 账 ...