loj6191「美团 CodeM 复赛」配对游戏 概率期望dp

Posted GXZlegend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj6191「美团 CodeM 复赛」配对游戏 概率期望dp相关的知识,希望对你有一定的参考价值。

题目描述

n次向一个栈中加入0或1中随机1个,如果一次加入0时栈顶元素为1,则将这两个元素弹栈。问最终栈中元素个数的期望是多少。

输入

一行一个正整数 n 。

输出

一行一个实数,表示期望剩下的人数,四舍五入保留三位小数。

样例输入

10

样例输出

4.168


题解

概率期望dp

显然任何时刻栈中的元素自底至顶一定是若干个0+若干个1。

但是如果设状态$p[i][j][k]$表示前$i$次操作,栈中$j$个0,$k$个1的概率,复杂度是$O(n^3)$的,显然会TLE。

注意到$0$的个数对状态转移是没有影响的,而期望在任何时刻都具有可加性,因此可以设$f[i][j]$表示前$i$次操作,栈中$j$个1的期望元素个数。

那么直接考虑新加入一个是0还是1,看一下长度是增加还是减少即可。

这里有一个问题:每次增加或减少的长度是多少?由于期望是概率*权值,这种情况的权值为1,因此期望值就是这种情况的概率。

所以还需要维护一个$p[i][j]$表示前$i$次操作,栈中$j$个1的概率。每次使用概率转移期望即可。

时间复杂度$O(n^2)$

#include <cstdio>
#define N 2010
double p[N][N] , f[N][N];
int main()
{
	int n , i , j;
	double ans = 0;
	scanf("%d" , &n) , p[0][0] = 1;
	for(i = 0 ; i < n ; i ++ )
	{
		p[i + 1][1] += p[i][0] / 2 , f[i + 1][1] += (f[i][0] + p[i][0]) / 2;
		p[i + 1][0] += p[i][0] / 2 , f[i + 1][0] += (f[i][0] + p[i][0]) / 2;
		for(j = 1 ; j < n ; j ++ )
		{
			p[i + 1][j + 1] += p[i][j] / 2 , f[i + 1][j + 1] += (f[i][j] + p[i][j]) / 2;
			p[i + 1][j - 1] += p[i][j] / 2 , f[i + 1][j - 1] += (f[i][j] - p[i][j]) / 2;
		}
	}
	for(i = 0 ; i <= n ; i ++ ) ans += f[n][i];
	printf("%.3lf\n" , ans);
	return 0;
}

 

以上是关于loj6191「美团 CodeM 复赛」配对游戏 概率期望dp的主要内容,如果未能解决你的问题,请参考以下文章

2017CodeM复赛

「美团 CodeM 复赛」城市网络

Loj #6164. 「美团 CodeM 初赛 Round A」数列互质

loj6177「美团 CodeM 初赛 Round B」送外卖2

美团CodeM资格赛第二题

CodeM美团点评编程大赛初赛A轮