[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)

题面

扔很多次硬币后,用H表示正面朝上,用T表示反面朝上,会得到一个硬币序列。比如HTT表示第一次正面朝上,后两次反面朝上。

选出n个同学,每个同学猜一个长度为m的序列,当某一个同学猜的序列在硬币序列中出现时(匹配时的序列必须连续),就不再扔硬币了,并且这个同学胜利。猜的n个序列两两不同。

假设硬币正反面朝上的概率相同,求每个同学胜利的概率。

\(n \leq 300\)

分析

(注意,本题中不区分序列和串,因为只讨论连续的情况)

设与所有猜的序列都不匹配的串S期望长度是H(这个定义比较玄学,虽然是无限抛下去的,但是理解的时候当成有限长度抛出这种不匹配的情况比较好理解)

引理: 结尾包含一个长度为L的确定的串但没有包含任意一个给定序列的概率为\(\frac{1}{2^L}\).

感性理解一下就好了,证明略.

那么在这样的S串后面加上第i个人猜的串\(A_i\),那么\(SA_i\)就有可能成为一个胜利的状态。根据引理,抛出\(SA_i\)的概率为\(\frac{H}{2^m}\)。但是,有可能提前抛出其他的串。如\(S=\mathrm{HTH},A_1=\mathrm{HTT},A_2=\mathrm{THT}\),那么当串为\(\mathrm{HTHT}\)时,在抛出\(A_1\)之前就会抛出\(A_2\).同样,如果S本来就包含\(A_i\)的一部分,也可能提前抛出\(A_i\)导致提前胜利。把提前胜利的情况从\(\frac{H}{2^m}\)里减掉,就可以得到第i个人在抛出\(SA_i\)时胜利的概率。

注意到如果提前抛出串\(A_j\),那么\(A_i\)的某个前缀和\(A_j\)的某个后缀一定相等(可能不止1个),比如HTT和THT的公共前后缀为TH。

设第\(i\)个人胜利的概率为\(p_i\),\(pre(S,i)\)表示串S长度为i的前缀,\(suf(S,i)\)表示串S长度为i的后缀。那么有

\[p_i=\frac{H}{2^m}-\sum_{j=1}^n \sum_{k=1}^{m-[i=j]} [pre(A_i,k)=suf(A_j,k)]p_j \frac{1}{2^{m-k}}
\]

解释一下\(\sum_{k=1}^{m-[i=j]} [pre(A_i,k)=suf(A_j,k)]\frac{1}{2^{m-k}}\)

我们枚举公共前后缀的长度k,当k确定时,\(pre(A_i,k)\)确定,那么后面长度为\(m-k\)的后缀也确定了。根据引理,这样的概率为\(\frac{1}{2^{m-k}}\)。

\(m-[i=j]\)的意义是, 当\(i=j\)时长度<=m-1时才是提前结束,如果长度为m,就是胜利的状态了。当\(k=m\)时,\([pre(A_i,k)=suf(A_i,k)]p_i \frac{1}{2^{m-k}}=p_i\),因此可以把左边的\(p_i\)去掉,然后把循环上界改成\(m\)

\[\frac{H}{2^m}-\sum_{j=1}^n \sum_{k=1}^{m} [pre(A_i,k)=suf(A_j,k)]p_j \frac{1}{2^{m-k}}=0
\]

移项,

\[\sum_{j=1}^n \sum_{k=1}^m [pre(A_i,k)=suf(A_j,k)]p_j\frac{1}{2^{m-k}}-\frac{H}{2^m}=0
\]

对于每个i,我们都可以得到这样一个方程。现在我们有\(p_1,p_2 \dots p_n,H\)共n+1个未知数,有n个方程.又因为\(\sum_{i=1}^n p_i=1\),我们就有n+1个方程了,直接高斯消元即可.suf和pre可以用哈希求。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define eps 1e-10
#define maxn 300
#define maxm 300
using namespace std;
typedef long long ll;
typedef double db;
int n,m;
char a[maxn+5][maxm+5]; const ll seed=2;
const ll mod=998244353;
ll hs[maxn+5][maxm+5];
ll pows[maxn+5]; db pow2[maxn+5];
void ini_hash(){
pow2[0]=1;
for(int i=1;i<=m;i++) pow2[i]=pow2[i-1]*0.5;
pows[0]=1;
for(int i=1;i<=m;i++) pows[i]=pows[i-1]*seed%mod;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) hs[i][j]=(hs[i][j-1]*seed+(a[i][j]=='T'))%mod;
}
}
db calc(int x,int y){
db ans=0;
for(int i=1;i<=m;i++){
if(hs[x][i]==(hs[y][m]-hs[y][m-i]*pows[i]%mod+mod)%mod) ans+=pow2[m-i];
}
return ans;
} db mat[maxn+5][maxm+5];
void gauss(int n,int m){
for(int i=1;i<=n;i++){
int id=i;
for(int j=i+1;j<=n;j++){
if(mat[j][i]>mat[id][i]) id=j;//把系数最大的行j交换到第i行
}
for(int k=1;k<=m;k++) swap(mat[i][k],mat[id][k]);
for(int j=1;j<=n;j++){
if(i==j) continue;
db r=mat[j][i]/mat[i][i];//把第j行第i个未知数的系数消成0
for(int k=i;k<=m;k++) mat[j][k]-=mat[i][k]*r;
}
}
for(int i=1;i<=n;i++){
mat[i][m]/=mat[i][i];
}
} int main(){
//#ifdef LOCAL
// freopen("game5.in","r",stdin);
//#endif
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
ini_hash();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mat[i][j]=calc(i,j); //1/2^(m-a)
}
mat[i][n+1]=-pow2[m];//H也是未知数
mat[i][n+2]=0;
}
for(int i=1;i<=n;i++) mat[n+1][i]=1;//sum(p[i])=1
mat[n+1][n+2]=1;
//#ifdef DEBUG
for(int i=1;i<=n+1;i++){
for(int j=1;j<=n+2;j++) printf("%.4f ",mat[i][j]);
printf("\n");
}
//#endif
gauss(n+1,n+2);
for(int i=1;i<=n;i++){
printf("%.10lf\n",mat[i][n+2]);
}
}

[BZOJ 4820] [SDOI2017] 硬币游戏(高斯消元+概率论+字符串hash)的更多相关文章

  1. [Sdoi2017]硬币游戏 [高斯消元 KMP]

    [Sdoi2017]硬币游戏 题意:硬币序列,H T等概率出现,\(n \le 300\)个人猜了一个长为$ m \le 300$的字符串,出现即获胜游戏结束.求每个人获胜概率 考场用了[1444: ...

  2. [BZOJ4820][SDOI2017]硬币游戏(高斯消元+KMP)

    比较神的一道题,正解比较难以理解. 首先不难得出一个(nm)^3的算法,对所有串建AC自动机,将在每个点停止的概率作为未知数做高斯消元即可. 可以证明,AC自动机上所有不是模式串终止节点的点可以看成一 ...

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

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

  4. BZOJ.4820.[SDOI2017]硬币游戏(思路 高斯消元 哈希/AC自动机/KMP)

    BZOJ 洛谷 建出AC自动机,每个点向两个儿子连边,可以得到一张有向图.参照 [SDOI2012]走迷宫 可以得到一个\(Tarjan\)+高斯消元的\(O((nm)^3)\)的做法.(理论有\(6 ...

  5. BZOJ 4820 [Sdoi2017]硬币游戏 ——期望DP 高斯消元

    做法太神了,理解不了. 自己想到的是建出AC自动机然后建出矩阵然后求逆计算,感觉可以过$40%$ 用一个状态$N$表示任意一个位置没有匹配成功的概率和. 每种匹配不成功的情况都是等价的. 然后我们强制 ...

  6. bzoj 4820: [Sdoi2017]硬币游戏【kmp+高斯消元】

    有点神,按照1444的做法肯定会挂 注意到它的概率是相同的,所以可以简化状态 详见http://www.cnblogs.com/candy99/p/6701221.html https://www.c ...

  7. BZOJ 4820 [SDOI2017] 硬币游戏

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

  8. 4820: [Sdoi2017]硬币游戏

    4820: [Sdoi2017]硬币游戏 链接 分析: 期望dp+高斯消元. 首先可以建出AC自动机,Xi表示经过节点i的期望次数,然后高斯消元,这样点的个数太多,复杂度太大.但是AC自动机上末尾节点 ...

  9. BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

    以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高 ...

随机推荐

  1. 一些简单题(2)(Source : NOIP历年试题+杂题)

    P3084 [USACO13OPEN]照片Photo 给出$m$个区间$[l_i,r_i]$覆盖$S=[1,n]$,试确定最大特殊点的数使得这每一个区间覆盖且仅覆盖一个特殊点. 如果无解,输出$-1$ ...

  2. Vue组件使用

    一.组件概念 有html模板,有css样式,有js逻辑的集合体 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的 ...

  3. MiracleSnow网页设计HTML5+CSS3+JS全套视频教程

    终于把这套课程讲完了,虽然时间隔了很长,但也算有始有终了,这是在YY讲课中我自己录的,讲了网页设计的基础,这也是我第一次给那么多人讲课,讲的不好多多包涵. 前几次视频和课件是分开的,后几次都打包在一起 ...

  4. [CSP-S模拟测试]:Cover(单调栈++单调队列+DP)

    题目传送门(内部题126) 输入格式 第一行两个个整数$n,m$表示区间的长度与彩灯的数量. 接下来$m$行,每行三个整数$l_i,r_i,a_i$表示一条彩灯能够覆盖的区间以及它的美观程度. 输出格 ...

  5. 揭开HTTPS的神秘面纱

    摘自:https://www.cnblogs.com/hujingnb/p/11789728.html 揭开HTTPS的神秘面纱   在说HTTP前,一定要先介绍一下HTTP,这家伙应该不用过多说明了 ...

  6. MySort(选做)的实现

    MySort(选做)的实现 题目内容 注意:研究sort的其他功能,要能改的动代码,需要答辩 模拟实现Linux下Sort -t : -k 2的功能. 要有伪代码,产品代码,测试代码(注意测试用例的设 ...

  7. Mimikatz 攻防杂谈

    前几天看到了老外一篇讲 mimikatz 防御的文章,感觉行文思路还不错,但是内容稍有不足,国内也有一篇翻译,但是只是照着错误翻译的,所以就萌生了把那篇优秀文章,翻译复现,并加入其它一些内容,本文只是 ...

  8. Input 输入框

    Input 输入框 通过鼠标或键盘输入字符 <el-input v-model="input" placeholder="请输入内容"></e ...

  9. 【MAC】安装chrome浏览器

    step1:下载dmg安装包 chrome下载地址 点击[下载Chrome] step2:安装chrome 下载好googlechrome.dmg文件后,像其它程序一样安装就可以了 打开访达--> ...

  10. oracle 12 安装

    oracle 12 第二版本安装 下载地址  https://www.oracle.com/technetwork/cn/middleware/webcenter/content/downloads/ ...