题目链接http://codeforces.com/gym/101174
题意
N N N 个球标号为 1 1 1 到 N N N,两个人分别写下 C C C 个数字,每次随机选出 D D D 个球,若干次后,如果某个人写的 C C C 个数字都出现过,则游戏结束。问游戏持续回合数的期望。
题解
概率DP。
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 的状态表示两个人的公共数字有 k k k 个还没被抽到,第一个人有 i i i 个数字没被抽到,第二个人剩 j j j 个。 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 的值表示这种状态下持续回合数的期望。
d p [ 0 ] [ j ] [ 0 ] dp[0][j][0] dp[0][j][0] 和 d p [ i ] [ 0 ] [ 0 ] dp[i][0][0] dp[i][0][0] 的答案都为 0 0 0,因为此时游戏已经结束了。
假设某一次抽球,抽到
x
x
x 个第一个人的数字,
y
y
y 个第二个人的,
z
z
z 个共有的,抽到这种情况的概率我们假设是
p
p
p :
p
=
C
i
x
×
C
j
y
×
C
k
z
×
C
n
−
i
−
j
−
k
d
−
x
−
y
−
z
C
n
d
p=\frac{C_i^x\times C_j^y\times C_k^z\times C_{n-i-j-k}^{d-x-y-z}}{C_n^d}
p=CndCix×Cjy×Ckz×Cn−i−j−kd−x−y−z
假设抽球并没有改变状态,概率是
q
q
q :
q
=
C
d
n
−
i
−
j
−
k
C
n
d
q=\frac{C_d^{n-i-j-k}}{C_n^d}
q=CndCdn−i−j−k
那么转移方程就可以写成:
d
p
[
i
]
[
j
]
[
k
]
=
(
d
p
[
i
−
x
]
[
j
−
y
]
[
k
−
z
]
+
1
)
p
+
(
d
p
[
i
−
x
]
[
j
−
y
]
[
k
−
z
]
+
2
)
p
q
+
⋯
+
(
d
p
[
i
−
x
]
[
j
−
y
]
[
k
−
z
]
+
n
)
p
q
n
−
1
dp[i][j][k]=(dp[i-x][j-y][k-z]+1)p+(dp[i-x][j-y][k-z]+2)pq+\cdots+(dp[i-x][j-y][k-z]+n)pq^{n-1}
dp[i][j][k]=(dp[i−x][j−y][k−z]+1)p+(dp[i−x][j−y][k−z]+2)pq+⋯+(dp[i−x][j−y][k−z]+n)pqn−1
为了方便起见,我们把
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k] 记为
S
S
S,
d
p
[
i
−
x
]
[
j
−
y
]
[
k
−
z
]
dp[i-x][j-y][k-z]
dp[i−x][j−y][k−z] 记为
d
p
dp
dp ,然后利用小学知识化简一下
S
=
(
d
p
+
1
)
p
+
(
d
p
+
2
)
p
q
+
⋯
+
(
d
p
+
n
)
p
q
n
−
1
q
S
=
(
d
p
+
1
)
p
q
+
(
d
p
+
2
)
p
q
2
+
⋯
+
(
d
p
+
n
)
p
q
n
\begin{aligned} S&=(dp+1)p+(dp+2)pq+\cdots+(dp+n)pq^{n-1}\\ qS&=(dp+1)pq+(dp+2)pq^2+\cdots+(dp+n)pq^{n} \end{aligned}
SqS=(dp+1)p+(dp+2)pq+⋯+(dp+n)pqn−1=(dp+1)pq+(dp+2)pq2+⋯+(dp+n)pqn
上式减下式得
(
1
−
q
)
S
=
(
d
p
+
1
)
p
+
p
q
+
p
q
2
+
⋯
+
p
q
n
−
1
−
(
d
p
+
n
)
p
q
n
S
=
(
d
p
+
1
)
p
+
p
q
(
1
−
q
n
−
1
)
1
−
q
−
(
d
p
+
n
)
p
q
n
1
−
q
\begin{aligned} (1-q)S&=(dp+1)p+pq+pq^2+\cdots+pq^{n-1}-(dp+n)pq^n\\ S&=\frac{(dp+1)p+p\frac{q(1-q^{n-1})}{1-q}-(dp+n)pq^n}{1-q}\\ \end{aligned}
(1−q)SS=(dp+1)p+pq+pq2+⋯+pqn−1−(dp+n)pqn=1−q(dp+1)p+p1−qq(1−qn−1)−(dp+n)pqn
然后根据大学知识可得
q
n
=
0
q^n=0
qn=0,最后化简成:
S
=
(
d
p
+
1
)
p
1
−
q
+
p
q
(
1
−
q
)
2
S=\frac{(dp+1)p}{1-q}+\frac{pq}{(1-q)^2}
S=1−q(dp+1)p+(1−q)2pq
所以,只要写六层转移就行了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
const int N=1e6+7;
db dp[60][60][60];
int n,d,c;
int a[60],b[60];
int na,nb,nc,nd;
int vis[60];
db fac[60];
db C(int n,int m){
if(n<m) return 0;
return fac[n]/fac[m]/fac[n-m];
}
int main()
{
fac[0]=fac[1]=1;
for(int i=2;i<=50;i++) fac[i]=fac[i-1]*i;
scanf("%d%d%d",&n,&d,&c);
for(int i=1;i<=c;i++) scanf("%d",&a[i]),vis[a[i]]+=1;
for(int i=1;i<=c;i++) scanf("%d",&b[i]),vis[b[i]]+=2;;
for(int i=1;i<=n;i++){
if(vis[i]==1) na++;
if(vis[i]==2) nb++;
if(vis[i]==3) nc++;
}
///printf("%d>>%d>>%d\n",na,nb,nc);
for(int i=0;i<=na;i++){
for(int j=0;j<=nb;j++){
for(int k=0;k<=nc;k++){
if(i==0&&k==0) continue;
if(j==0&&k==0) continue;
for(int x=0;x<=i&&x<=d;x++){
for(int y=0;y<=j&&x+y<=d;y++){
for(int z=0;z<=k&&x+y+z<=d;z++){
if(x==0&&y==0&&z==0) continue;
int oth=n-i-j-k;
db p=C(i,x)*C(j,y)*C(k,z)*C(oth,d-x-y-z)/C(n,d);
db q=C(oth,d)/C(n,d);
///printf("p=%f q=%f\n",(double)p,(double)q);
dp[i][j][k]+=((dp[i-x][j-y][k-z]+1)*p+p*q/(1-q))/(1-q);
}
}
}
///printf("dp[%d][%d][%d]=%f\n",i,j,k,(double)dp[i][j][k]);
}
}
}
printf("%.10f\n",(double)dp[na][nb][nc]);
}