[LnOI2019]加特林轮盘赌

VI.[LnOI2019]加特林轮盘赌

我们考虑设\(f[i][j]\)表示\(i\)个人中,第\(j\)个人最终存活的概率。

我们先考虑\(j>1\)的情况。此时,有\(p\)的概率排在首位的人挂掉,局面变为\(f[i-1][j-1]\);反之,有\(1-p\)的概率首位存活,这就相当于所有人向前进一格,局面变为\(f[i][j-1]\)

于是我们有

\[f[i][j]=p\times f[i-1][j-1]+(1-p)\times f[i][j-1]\qquad(1<j\leq i) \]

下面我们考虑特殊情况\(f[i][1]\)。显然,只有这一枪他幸存下来了,他最终才有可能存活。故我们有

\[f[i][1]=(1-p)f[i][i] \]

到这里我们就可以DP了。我们初始有\(f[1][1]=1\);接着,我们从小往大枚举\(i\),更新DP状态。

我们设\(f[i][1]=a\times f[i][i]+b\)。显然,此时有\(a=1-p,b=0\)。这样,我们就可以把\(f[i][2]\)表示成\(c\times f[i][i]+d\)的形式,接着把\(f[i][3]\)表示成\(e\times f[i][i]+f\)的形式……

最终,我们得到一个方程:

\[f[i][i]=x\times f[i][i]+y \]

直接解该方程即可得出\(f[i][i]\)。再DP一圈即可得出所有的\(f[i][j]\)

时间复杂度\(O(n^2)\)。(注意特判\(p=0\)时的情况)

代码:

#include<bits/stdc++.h>
using namespace std;
const long double eps=1e-9;
int n,m;
long double p,f[2][10100];
int main(){
	cin>>p>>n>>m;
	if(p<eps){if(m==1)puts("1");else puts("0");return 0;}
	f[1][1]=1;
	for(int i=2;i<=n;i++){
		double a=1,b=0;
		for(int j=1;j<=i;j++)a*=1-p,b=(1-p)*b+p*f[!(i&1)][j-1];
		f[i&1][i]=b/(1-a);
		f[i&1][1]=(1-p)*f[i&1][i];
		for(int j=2;j<i;j++)f[i&1][j]=(1-p)*f[i&1][j-1]+p*f[!(i&1)][j-1];
	}
	printf("%.10Lf\n",f[n&1][m]);
	return 0;
} 

posted @ 2021-04-02 15:23  Troverld  阅读(45)  评论(0编辑  收藏  举报