题目链接


问题分析

首先一个显然的做法就是建出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\)个方程

\[P_i=\frac{1}{2^m}P_0-\sum_{j=1}^n\sum_{k=1}^m[substr(i,1,k)=substr(j,m-k+1)]\frac{1}{2^{m-k}}P_j
\]

其中\(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」硬币游戏的更多相关文章

  1. @loj - 2004@ 「SDOI2017」硬币游戏

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数 ...

  2. 题解 「SDOI2017」硬币游戏

    题目传送门 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利. 大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了. 同学们觉得要加强 ...

  3. 【LOJ 2004】「SDOI2017」硬币游戏

    LOJ 2004 100pts 首先我们肯定要建AC自动机的.. 那么这题就肯定是个AC自动机上\(dp\). 所以想想状态. 首先如果我们把状态设成这样行不行: \(dp(i)\)表示匹配到了i节点 ...

  4. 【LOJ】#2067. 「SDOI2016」硬币游戏

    题解 c一样的就是一个独立的游戏 我们对于2和3的指数 sg[i][j] 表示\(c \cdot 2^i \cdot 3^j\)的棋子,只有这个硬币是反面,翻转的硬币是正面的sg值 枚举sg函数所有可 ...

  5. 「SDOI2017」树点涂色 解题报告

    「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...

  6. LibreOJ 2003. 「SDOI2017」新生舞会 基础01分数规划 最大权匹配

    #2003. 「SDOI2017」新生舞会 内存限制:256 MiB时间限制:1500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  7. AC日记——「SDOI2017」序列计数 LibreOJ 2002

    「SDOI2017」序列计数 思路: 矩阵快速幂: 代码: #include <bits/stdc++.h> using namespace std; #define mod 201704 ...

  8. 【LOJ】#2269. 「SDOI2017」切树游戏

    题解 把所有的数组一开始就FWT好然后再IFWT回去可以减小常数 从13s跑到0.7s-- 可以参照immortalCO的论文,感受一下毒瘤的动态动态DP 就是用数据结构维护线性递推的矩阵的乘积 由于 ...

  9. loj#2269. 「SDOI2017」切树游戏

    还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...

随机推荐

  1. 两两内积为0(牛客多校第七场)-- CDMA

    题意: 构造一个n*n的矩阵,元素只能是-1或1,任意两行内积为0(两两相乘加起来和为0). 思路: #define IOS ios_base::sync_with_stdio(0); cin.tie ...

  2. c++学习之对象和类——构造函数和析构函数

    再认真理一遍~ 0.类 这里先来定义一个类,便于后面的理解.参考C++ Primer Plus class Stock { private: std::string company; long sha ...

  3. Memcached安装 常用指令

    Memcached 源码安装 # 安装依赖yum install -y gcc gcc-c++ automake autoconf make cmake libevent-devel.x86_64# ...

  4. Oracle Help 类

    public static string ConnString = @"Data Source=xxx;USER ID=xxx;PASSWORD=xxx"; /// <sum ...

  5. 110、通过案例学习Secret (Swarm17)

    参考https://www.cnblogs.com/CloudMan6/p/8098761.html   在下面的例子中,我们会部署一个 WordPress 应用,WordPress 是流行的开源博客 ...

  6. bilibili小程序项目总结

    1.关于mock的使用 第一步:先到Mock官网(http://mockjs.com/)上面熟悉一下基本用法 第一步:具体使用实例: 下载wxMock.js和mock.js文件 下载地址:https: ...

  7. angular装饰器

    @NgModule 元数据 NgModule 是一个带有 @NgModule() 装饰器的类.@NgModule() 装饰器是一个函数,它接受一个元数据对象,该对象的属性用来描述这个模块.其中最重要的 ...

  8. mysql explain解析一 extra中的using index,using where,using index condition

    1.简单介绍 using index 和using where只要使用了索引我们基本都能经常看到,而using index condition则是在mysql5.6后新加的新特性,我们先来看看mysq ...

  9. c++ 指定目录下的文件遍历

    要实现指定目录下文件的遍历需要执行一下的部分: 第一步获取当前路径的名字:(MAX_PATH是在windows定义的所有的路径名字不超过其,调用该函数会使得得到当前的目录) #include < ...

  10. 你所不知的VIM强大功能

    1. 可视化区块(Visual Block) (1)cd ~ 切换到自己的家目录(本范例中为root用户) (2)touch test1 test2 建立两个文件做演示(3)last > tes ...