CF540D

Bad Luck Island

如果把问题看作简单抽球,算出来的概率方程会把 $f( i , j , k )$ 消掉。。。

并不知道是为什么,这题好像要把抽到相同种类的球的概率去掉才能正常计算。

定义 $f ( i , j , k )$ 表示最后剩下 $i$ 个石头,$j$ 个剪刀,$k$ 个布的概率。

显然 $f ( r , s , p ) = 1 $,$i,j,k$ 中任意数目大于其对应上限的概率都是 $0$。

然后直接转移就好了:

$$
\begin{aligned}
f ( i , j , k )
= &
\dfrac { 2 ( i + 1 ) k } { t + 2 j + 2 k } f ( i + 1 , j , k ) +
\\
& \dfrac{ 2 ( j + 1 ) i } { t + 2 i + 2 k } f ( i , j + 1 , k ) +
\\
& \dfrac { 2 ( k + 1 ) j } { t + 2 i + 2 j } f ( i , j , k + 1 )
\end{aligned}
$$

这里直接记忆化就行了,最后把单个物种能存活的概率累加起来就是答案。

时间复杂度 $ O( n ^ 3 ) $。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
#include<cstdio>
#define ll long long
#define ld long double
using namespace std;
namespace Ehnaev{
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
return ret*f;
}
inline void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
while(len>=0) putchar(buf[len--]);
}
}using Ehnaev::read;using Ehnaev::write;

const ll N=1e2;

ll r,s,p;
ld ansr,anss,ansp;
ld f[N+5][N+5][N+5];
bool vis[N+5][N+5][N+5];

inline ld DP(ll i,ll j,ll k) {
if(i>r||j>s||k>p) return 0;
if(vis[i][j][k]) return f[i][j][k];vis[i][j][k]=1;
ll t=2*(i*j+j*k+i*k);ld res=0;
if(t+2*(j+k)>0) res+=(2*i*k+2*k)/(ld)(t+2*(j+k))*DP(i+1,j,k);
if(t+2*(i+k)>0) res+=(2*i*j+2*i)/(ld)(t+2*(i+k))*DP(i,j+1,k);
if(t+2*(i+j)>0) res+=(2*k*j+2*j)/(ld)(t+2*(i+j))*DP(i,j,k+1);
return f[i][j][k]=res;
}

int main() {

r=read();s=read();p=read();
f[r][s][p]=1;vis[r][s][p]=1;

for(ll i=1;i<=r;i++) {ansr+=DP(i,0,0);}
for(ll i=1;i<=s;i++) {anss+=DP(0,i,0);}
for(ll i=1;i<=p;i++) {ansp+=DP(0,0,i);}

printf("%.12Lf %.12Lf %.12Lf",ansr,anss,ansp);

return 0;
}