P5249 [LnOI2019]加特林轮盘赌

题目

题目

思路

期望dp。
a i , j a_{i,j} ai,j为前i个人中,第j个人活到最后的情况。
显然有:
a i , j = P ∗ a i − 1 , j − 1 + ( 1 − P ) ∗ a i , j − 1 , 1 < = i < = n , 1 < = j < = i a_{i,j}=P*a_{i-1,j-1}+(1-P)*a_{i,j-1},1<=i<=n,1<=j<=i ai,j=Pai1,j1+(1P)ai,j1,1<=i<=n,1<=j<=i
同时有:
∑ j = 1 i a i , j = 1 \sum^{i}_{j=1}a_{i,j}=1 j=1iai,j=1
那么这里一共n个方程,全部高斯消元?
TLE妥妥地
所以我们不能用高斯消元,那么我们如何提速呢?
n只有 1 0 4 10^4 104,所以可以n方算法,这么说这里计算方程只能O(n)了?
没错,当然是O(n)!
按循环顺序,显然方程第一项是个常数了,我们只需要考虑后面的,运用递归知识(这里O(n)),我们可以求出一个这样的柿子:
x ∗ a i , 1 + y = 1 x*a_{i,1}+y=1 xai,1+y=1,进一步可得 a i , 1 a_{i,1} ai,1,这里就可以递推出 a i , 2 … … a i , i a_{i,2}……a_{i,i} ai,2ai,i.
不要忘记特判 P P P为0的情况。
code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue> 
using namespace std;
double p,a[10010],b[10010],c,d,lc,ld;
int n,k;
void f(int x)
{
    
    
	if (x==1)
	{
    
    
		c=1,d=0,
		lc=1,ld=0;
		return;
	}
	f(x-1);
	c=(1-p)*c;
	d=p*b[x]+(1-p)*d;
	lc+=c,ld+=d;
	return;
}
int main()
{
    
    
	cin>>p>>n>>k;
	if (p==0)//加特林瓦特了
	{
    
    
		cout<<(n<=1);
		return 0;
	}
	b[2]=a[1]=1;
	for (int i=2;i<=n;i++)
	{
    
    
		f(i);
		a[1]=(1-ld)/lc;
		for (int j=2;j<=i;j++) a[j]=p*b[j]+(1-p)*a[j-1];
		for (int j=2;j<=i+1;j++) b[j]=a[j-1];
	}
	printf("%.12lf",a[k]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_49843717/article/details/115258984