博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 4820 [SDOI2017] 硬币游戏
阅读量:6831 次
发布时间:2019-06-26

本文共 2941 字,大约阅读时间需要 9 分钟。

Description

  周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了。同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况。用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列。比如HTT表示第一次正面朝上,后两次反面朝上。但扔到什么时候停止呢?大家提议,选出\(n\)个同学,每个同学猜一个长度为\(m\)的序列,当某一个同学猜的序列在硬币序列中出现时,就不再扔硬币了,并且这个同学胜利,为了保证只有一个同学胜利,同学们猜的\(n\)个序列两两不同。很快,\(n\)个同学猜好序列,然后进入了紧张而又刺激的扔硬币环节。你想知道,如果硬币正反面朝上的概率相同,每个同学胜利的概率是多少。

Input

  第一行两个整数\(n,m\)

  接下里n行,每行一个长度为m的字符串,表示第i个同学猜的序列。
  \(1<=n,m<=300\)

Output

  输出n行,第i行表示第i个同学胜利的概率。

  输出与标准输出的绝对误差不超过\(1e-6\)即视为正确。

Sample Input

3 3

THT
TTH
HTT

Sample Output

0.3333333333

0.2500000000
0.4166666667

数据规模

\(1\leq n,m \leq 300\)

乍一看是 [JSOI2009]有趣的游戏,但是数据范围不支持。于是标解就用了个十分神仙的方法减少了方程数。

我们还是从 [JSOI2009]有趣的游戏 的思路开始分析。我们发现中间状态太多了,所以我们将转移到中间状态的期望设为\(x_0\)。然后\(x_i (1\leq i \leq n)\)表示第\(i\)个人胜利的期望。

因为该题依然期望\(=\)概率,所以依然有\(x_1+x_2+...+x_n=1\)

然后就是最神仙的方程了。

我们设\(P(i)\)表示在游戏中途(未结束时)出现的所有字符串后面接上第\(i\)个字符串得到的字符串出现的期望。

首先,\(P(i)=\frac{1}{2^m}x_0 .\)我们在任意一个中间状态后面加上第\(i\)个字符串,就可以得到想要的结果。因为每种字符出现概率相同,所以出现第\(i\)个串的概率为\(\frac{1}{2^m}\)。我们再考虑用用其他的变量表示\(P(i)\)

显然出现了这种字符串代表游戏一定结束了,但是游戏不一定在这个时候结束,赢家不一定是\(i\),因为可能在插入第\(i\)个串的中途就匹配上了一个字符串。我们发现出现这种情况一定是一个字符串\(j\)的长度为\(k(1\leq k < m)\)的后缀与\(i\)字符串的长度为\(k\)的前缀相同(注意这里\(j\)是可以等于\(i\)的)。画个图就很好理解了。

然后再在后面补上\(m-k\)个字符就可以了。这部分的概率是\(\frac{1}{2^{m-k}}\)

我们考虑出现上述情况的时候赢家一定是\(j\),所以第\(i\)个字符串对\(P(i)\)的贡献就是\(g(i,j)=\displaystyle \sum_{k=1}^{m-1}[j的k后缀=i的k前缀]\frac{1}{2^{m-k}}\)

快速求出所有\(k\)可以考虑用\(kmp\)

于是我们有列出了\(n\)个方程:$\displaystyle \sum_{j=1}^ng(i,j)x_j+x_i=\frac{1}{2^m}x_0 $。

然后解方程就行了。

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long#define ld long double#define N 305using namespace std;inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}int n,m;char s[N][N];ld a[N][N],pw[N];int nxt[N];void Get_nxt(char *s) { memset(nxt,0,sizeof(nxt)); nxt[0]=-1; for(int i=1;i<=m;i++) { int j=nxt[i-1]; while(j!=-1&&s[j+1]!=s[i]) j=nxt[j]; nxt[i]=j+1; }}ld cal(char *s,char *t) { int now=0; ld ans=0; for(int i=1;i<=m;i++) { while(now!=-1&&s[now+1]!=t[i]) now=nxt[now]; now++; } if(now==m) now=nxt[now]; while(now) { ans+=pw[m-now]; now=nxt[now]; } return ans;}ld ans[N];void Guass() { for(int i=0;i<=n;i++) { for(int j=i;j<=n;j++) if(fabs(a[i][i])
=1;i--) { for(int j=n;j>i;j--) { a[i][n+1]-=ans[j]*a[i][j]; } ans[i]=a[i][n+1]/a[i][i]; }}int main() { n=Get(),m=Get(); pw[0]=1; for(int i=1;i<=m;i++) pw[i]=pw[i-1]*0.5; for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) a[0][i]=1; a[0][n+1]=1; for(int i=1;i<=n;i++) { Get_nxt(s[i]); for(int j=1;j<=n;j++) { a[i][j]=cal(s[i],s[j]); } a[i][0]=-pw[m]; a[i][i]++; } Guass(); for(int i=1;i<=n;i++) cout<
<
<
<<"\n"; return 0;}

转载于:https://www.cnblogs.com/hchhch233/p/10356868.html

你可能感兴趣的文章
Handbook of Constraints Programming——Chapter4 Backtracking Search Algorithms-Preliminaries
查看>>
[转载] 信息系统项目管理师视频教程——14 项目进度管理
查看>>
linux 解压文件
查看>>
Ansible入门
查看>>
SVN学习总结(1)——SVN简介及入门使用
查看>>
浅谈linux性能调优之五:调优软raid
查看>>
Android sdk下载缓慢解决方式
查看>>
IBM TPC强化中国建设银行存储管理能力
查看>>
常用ftp子命令的总结
查看>>
正则表达式
查看>>
在 JS 中使用 fetch 更加高效地进行网络请求
查看>>
javascript 分页算法
查看>>
android手机root后的安全问题
查看>>
bat改ip
查看>>
SpringBoot之在Servlet2.5容器中部署war应用
查看>>
项目申请文档提纲
查看>>
加密解密第二章:ollydbg用法
查看>>
百万PV网站架构
查看>>
N26-第四周作业
查看>>
在vmware安装Ubuntu桌面软件
查看>>