这是一道概率问题,可以使用动态规划来解决。具体地,设 $f_{i,j,k}$ 表示经过 $k$ 次魔法操作后,小明还剩下 $i$ 堆石子,小亮还剩下 $j$ 堆石子,且小亮的每一堆石子都不剩余的概率。则所求的答案为 $f_{n,m,d}$。
初始时,$f_{i,j,0}=1$,表示还没有进行任何魔法操作,小亮一堆石子都不剩余的概率为1。
接下来考虑如何进行状态转移。每次魔法操作会随机选择一堆石子,并将其中一个石子拿走。因此,对于当前的状态 $f_{i,j,k}$,可以考虑从中选择一堆石子,将其中一个石子拿走,然后转移到下一个状态 $f_{i-1,j,k+1}$ 或 $f_{i,j-1,k+1}$。需要注意的是,如果选择的石子已经没有剩余的石子了,则不能再进行魔法操作。
根据上述状态转移方程,可以使用动态规划求解出所有状态,最终得到 $f_{n,m,d}$ 即可。时间复杂度为 $O(n^3md)$。
以下是 C++ 的代码实现:
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
const int N = 6, M = 105;
double f[N][N][M];
int n, m, d;
int a[N], b[N];
int main()
{
cin >> n >> m >> d;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++) cin >> b[i];
memset(f, 0, sizeof(f));
f[n][m][0] = 1; // 初始状态
for (int k = 1; k <= d; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
double p = 1.0 / (n + m - k + 1);
if (a[i] >= k && i <= n) f[i-1][j][k] += f[i][j][k-1] * p;
if (b[j] >= k && j <= m) f[i][j-1][k] += f[i][j][k-1] * p;
}
}
}
cout << fixed << setprecision(4) << f[0][0][d] << endl;
return 0;
}
其中,$p$ 表示随机选择一堆石子的概率,为 $\frac{1}{n+m-k+1}$。为了便于处理,数组下标从 1 开始计算。注意,由于小明和小亮的每一堆石子所包含的石子个数均不超过6,因此可以使用一个 6 维数组来存储状态,但是这样会占用过多的空间,不太实际,因此可以将数组的第三维缩小到 $d+1$。
最后输出的结果需要保留四位小数,可以使用 fixed 和 setprecision 函数来实现。
|