CodeForces - 28C Bath Queue 概率与期望

2024-04-03 07:38

本文主要是介绍CodeForces - 28C Bath Queue 概率与期望,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我概率期望真是垃圾……,这题搞了两个钟头……

题意

\(n\)个人,\(m\)个浴室,每个浴室里有\(a_i\)个浴缸。每个人会等概率随机选择一个浴室,然后每个浴室中尽量平分到每个浴缸。问期望最长排队队伍长度是多少?

解题思路

我看网上的题解都是直接\(DP\)期望,然而本蒟蒻看不懂那个递推式是什么鬼……有没有\(dalao\)来解释一下啊……
付一下别人的题解,摘自https://www.cnblogs.com/LzyRapx/p/7692702.html
用状态$ dp[i][j][k] \(表示还剩\) i$ 间浴室,还剩 \(j\) 个人,之前最长队伍的长度为 \(k\) 的期望最长队伍长度。
那么状态转移方程为:
\[ dp[i][j][k]=∑^m_{i=1}∑^n_{j=0}∑^n_{k=1}∑^j_{c=1}(dp[i−1][j−c][max(k,(c+a[i]−1)/a[i])]\times (i−1)^{j−c}/i^j \times (j,c)) \]
其中 \(c\) 是枚举当前去第 \(j\) 间浴室的人数。
那么答案就是$ dp[m][n][0]$ 。

----伪分割线----

下面是我自己的概率做法。
我们令\(dp[i][j][k]\)表示已经选了\(i\)个浴室,还剩\(j\)个人,最长长度为\(k\)的概率。注意下标意义的定义与上面的不一样。
那么我们可以得到状态转移方程:
\[ dp[i+1][j-c][max(k, \frac{c+a[i+1]-1}{a[i+1]})] += dp[i][j][k]\times {j \choose c} / m^c \]
这里感谢\(PSCdalao\)帮我斧正这个方程,并阐述了为什么是除以\(m^c\)
下面我们解释这个方程的意义。
现在在状态\(dp[i][j][k]\),那么我们可以从剩下\(j\)个人中,选出\(c\)个。这时候下标就变为了\(dp[i+1][j-c][max(k, \frac{c+a[i+1]-1}{a[i+1]})]\)。而从前一个状态转到这一个方案的概率就是\({j \choose c} / m^c\)(从\(j\)个人中选\(c\)个,而这\(c\)个人本来可以有\(m^c\)种选法)。我们再来仔细看一下为什么是\(m^c\)而不是\((m-i)^c\)
我们把n个人分到m个澡堂的某种分法的概率应当为
\[ \frac{{n\choose p_1}{n-p_1\choose p_2}{n-p_1-p_2\choose p_3}...}{m^n} \]
然后我们拆开分别乘在每一步中,就成了
\[ \frac{{n\choose p_1}}{m^{p_1}} \times \frac{{n-p_1\choose p_2}}{m^{p_2}} \times \frac{{n-p_1-p_2\choose p_3}}{m^{p_3}}... \]
所以就有方程中的“\(/m^c\)”。
同时,我们可以看出,我们同样可以先求出方案数,最后再除以\(m^c\)。(感谢\(DYTdalao\)提供这个好主意)

到这里,我们求出了概率。最后把每一个概率乘以长度,累加就好了。

不要问我精度问题,反正全部开\(double\),然后什么都不管就可以了QwQ

参考程序

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int Maxn = 60;
int n, m, a[ Maxn ];
double dp[ Maxn ][ Maxn ][ Maxn ], C[ 60 ][ 60 ];double Power( double x, int y ) {if( y == 0 ) return 1.0;double t = Power( x, y / 2 );t = t * t;if( y % 2 == 1 ) t = t * x;return t;
}void init() {memset( C, 0, sizeof( C ) );C[ 0 ][ 0 ] = 1.0;for( int i = 1; i <= 50; ++i ) {C[ i ][ 0 ] = 1.0;for( int j = 1; j <= i; ++j ) C[ i ][ j ] = C[ i - 1 ][ j - 1 ] + C[ i - 1 ][ j ];}return;
}int main() {init();memset( dp, 0, sizeof( dp ) );scanf( "%d%d", &n, &m );dp[ 0 ][ n ][ 0 ] = 1.0;for( int i = 1; i <= m; ++i ) scanf( "%d", &a[ i ] );for( int i = 0; i < m - 1; ++i ) for( int j = 0; j <= n; ++j ) for( int k = 0; k <= n; ++k )for( int c = 0; c <= j; ++c ) dp[ i + 1 ][ j - c ][ max( k, ( c + a[ i + 1 ] - 1 ) / a[ i + 1 ] ) ] += dp[ i ][ j ][ k ] * C[ j ][ c ] / Power( m * 1.0, c );for( int j = 0; j <= n; ++j )for( int k = 0; k <= n; ++k ) dp[ m ][ 0 ][ max( k, ( j + a[ m ] - 1 ) / a[ m ] ) ] += dp[ m - 1 ][ j ][ k ] * 1.0 / Power( m * 1.0, j );double ans;for( int i = 0; i <= n; ++i )ans += i * dp[ m ][ 0 ][ i ];printf( "%.10lf\n", ans );return 0;
}

转载于:https://www.cnblogs.com/chy-2003/p/9646712.html

这篇关于CodeForces - 28C Bath Queue 概率与期望的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/872298

相关文章

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

ActiveMQ—Queue与Topic区别

Queue与Topic区别 转自:http://blog.csdn.net/qq_21033663/article/details/52458305 队列(Queue)和主题(Topic)是JMS支持的两种消息传递模型:         1、点对点(point-to-point,简称PTP)Queue消息传递模型:         通过该消息传递模型,一个应用程序(即消息生产者)可以

Java-数据结构-栈和队列-Stack和Queue (o゚▽゚)o

文本目录: ❄️一、栈(Stack):     ▶ 1、栈的概念:   ▶ 2、栈的使用和自实现:      ☑ 1)、Stack():       ☑ 2)、push(E e):      ☑ 3)、empty():         ☑ 4)、peek(E e):        ☑ 5)、pop(E e):       ☑ 6)、size(E e):  ▶ 3、栈自实现的总代

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>