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

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

description

周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利。

大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了。

同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况。

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

但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某一个同学猜的序列在硬币序列中出现时,就不再扔硬币了,并且这个同学胜利,为了保证只有一个同学胜利,同学们猜的n个序列两两不同。

很快,n个同学猜好序列,然后进入了紧张而又刺激的扔硬币环节。你想知道,如果硬币正反面朝上的概率相同,每个同学胜利的概率是多少。

data range

\[1≤n,m≤300\]

solution

概率生成函数

\[f(x)=Pr(x=i)x^i\]

\(Pr(x=i)\)表示\(x\)\(i\)时的概率。
有一个很好的性质:
\[E(x)=\sum_{i=1}^{\infty}iPr(x=i)=f'(1)\]

\(F_i(x)\)表示关于第\(i\)个序列的成功生成函数,\(G(x)\)表示关于第\(i\)个序列的未成功生成函数,

我们要求的是\(F_i(1)\)

考虑性质,得出

\[\sum_{i=1}^{n}F_i(x)+G(x)=xG(x)+1\]

\[G(x)(\frac{1}{2}x)^m=\sum_{j=1}^{n}\sum_{k=1}^{m}a_{i,j,k}F_j(x)(\frac{1}{2}x)^{m-k}\]

其中\(a_{i,j,k}\)表示第\(i\)个序列的前\(k\)位是否为第\(j\)个序列的后\(k\)

对第一个式子求导,得出

\[\sum_{i=1}^{n}F_i'(x)=G(x)\]

\(x=1\)代入第二个式子,得出

\[G(1)=\sum_{j=1}^{n}\sum_{k=1}^{m}a_{i,j,k}2^kF_j(1)\]

再由

\[\sum_{i=1}^{n}F_i(1)=1\]

这样就有\((n+1)\)个式子可以求解\(F_i(1)\)\(G(1)\)

code

顺手写了一波从未写过的哈希

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FILE "a"#define mp make_pair#define pb push_back#define RG register#define il inlineusing namespace std;typedef unsigned long long ull;typedef vector
VI;typedef long long ll;typedef double dd;const dd eps=1e-10;const int mod=1e9+7;const int N=310;const dd pi=acos(-1);const int inf=2147483647;const ll INF=1e18+1;il ll read(){ RG ll data=0,w=1;RG char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar(); return data*w;}il void file(){ srand(time(NULL)+rand()); freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout);}dd S[N][N];il void gauss(int n){ for(RG int i=1;i<=n;i++){ if(abs(S[i][i])<=eps) for(RG int j=i+1;j<=n;j++) if(abs(S[j][i])>eps) {swap(S[i],S[j]);break;} for(RG int j=i+1;j<=n;j++) for(RG int k=n+1;k>=i;k--) S[j][k]-=S[i][k]*S[j][i]/S[i][i]; } for(RG int i=n;i;i--){ for(RG int j=n;j>i;j--){ S[i][n+1]-=S[i][j]*S[j][n+1]; S[i][j]=0; } S[i][n+1]/=S[i][i]; S[i][i]=1; }}ll n,m,pw[N],s[N][N],h[N][N];il int hash(int i,int l,int r){ return (h[i][r]-1ll*h[i][l-1]*pw[r-l+1]%mod+mod)%mod;}bool a[N][N][N];dd pww[N];int main(){ n=read();m=read();RG char c;pw[0]=pww[0]=1; for(RG int i=1;i<=m;i++) pw[i]=2ll*pw[i-1]%mod,pww[i]=pww[i-1]*2; for(RG int i=1;i<=n;i++) for(RG int j=1;j<=m;j++){ c=0;while(c!='T'&&c!='H')c=getchar(); s[i][j]=(c=='H'); h[i][j]=(2ll*h[i][j-1]%mod+s[i][j])%mod; } for(RG int i=1;i<=n;i++) for(RG int j=1;j<=n;j++) for(RG int k=1;k<=m;k++) a[i][j][k]=(hash(i,1,k)==hash(j,m-k+1,m)); for(RG int i=1;i<=n;i++){ for(RG int j=1;j<=n;j++) for(RG int k=1;k<=m;k++) S[i][j]+=a[i][j][k]*pww[k]; S[i][n+1]=-1; } for(RG int i=1;i<=n;i++)S[n+1][i]=1;S[n+1][n+2]=1; gauss(n+1); for(RG int i=1;i<=n;i++)printf("%.10lf\n",S[i][n+2]); return 0;}

转载于:https://www.cnblogs.com/cjfdf/p/9318497.html

你可能感兴趣的文章
Unity学习笔记—— 常用脚本函数
查看>>
.getCellType()的几种类型值
查看>>
linux中启动 java -jar 后台运行程序
查看>>
运行web项目端口占用问题
查看>>
Java Spring-IOC和DI
查看>>
【NOIP1999】【Luogu1015】回文数(高精度,模拟)
查看>>
Linux上安装Python3.5
查看>>
crt安装
查看>>
git切换分支报错:error: pathspec 'origin/XXX' did not match any file(s) known to git
查看>>
c++中static的用法详解
查看>>
转 我修改的注册表,但是程序运行起来,还是记着以前的
查看>>
图片轮播功能
查看>>
第六周小组作业:软件测试和评估
查看>>
UVA2636
查看>>
PHP环境搭建所遇到的问题
查看>>
Flash开发移动设备技巧
查看>>
QQ西游内存数据分析-2012年9月28日
查看>>
Arrays类——Arrays.asList()方法使用
查看>>
linux Cacti监控服务器搭建
查看>>
什么是2.5D与3D编辑模式
查看>>