【题意】:略。

【题解】:设dp[i][j]表示左边有i个洞亮,右边有j个洞亮离目标状态的期望。
               然后所有dp[ii][jj](ii >= i && jj >= j)都是dp[i][j]的后继状态,由期望计算公式可以算出dp[i][j]的期望。
               这里转移会有个环,移项即可处理掉。
               要先预处理组合数、p的幂和(1-p)的幂。
               最后答案即为dp[0][0].
               用记忆化搜索来写非常方便。

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 #include "string"
 9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 using namespace std;
13 #define pb push_back
14 #define mp make_pair
15 #define fi first
16 #define se second
17 #define lc(x) (x << 1)
18 #define rc(x) (x << 1 | 1)
19 #define lowbit(x) (x & (-x))
20 #define ll long long
21 #define maxn 110
22 double dp[55][55];
23 double p1[maxn], p2[maxn];
24 double C[55][55];
25 int n, m;
26 double p;
27 bool visit[55][55];
28 void init() {
29     for(int i = 0; i < 51; i++) C[i][0] = C[i][i] = 1;
30     for(int i = 2; i < 51; i++)
31         for(int j = 1; j < i; j++)
32             C[i][j] = C[i-1][j-1] + C[i-1][j];
33 }
34 
35 double dfs(int a, int b) {
36     double &tmp = dp[a][b];
37     if(visit[a][b]) return tmp;
38     visit[a][b] = true;
39     if(a >= m && b >= m) return tmp = 0.0;
40     tmp = 1.0;
41     for(int i = 0; i <= n - a; i++) {
42         for(int j = 0; j <= n - b; j++) {
43             if(i == 0 && j == 0) continue;
44             tmp += (dfs(a + i, b + j)) * p1[i+j] * p2[2 * n - a - b - i - j] * C[n-a][i] * C[n-b][j];
45         }
46     }
47     return tmp /= (1 - p2[2 * n - a - b]);
48 }
49 
50 int main() {
51     init();
52     while(~scanf("%d%d%lf", &n, &m, &p)) {
53         if(!n && !m) break;
54         p1[0] = p2[0] = 1.0;
55         for(int i = 1; i < maxn; i++) p1[i] = p1[i-1] * p;
56         for(int i = 1; i < maxn; i++) p2[i] = p2[i-1] * (1 - p);
57         memset(visit, falsesizeof(visit));
58         printf("%.6f\n", dfs(0, 0));
59     }
60     return 0;
61 }
62