HDU-5985 Lucky Coins (概率)

题目链接:HDU-5985 Lucky Coins

题意

给出 n 种硬币,已知每种硬币的个数和抛掷后正面朝上的概率,每次将所有硬币抛掷,背面朝上的丢弃,直到只剩下一种硬币被称为幸运硬币,问每种硬币成为幸运硬币的概率。


思路

(f[i][k]) 表示第 (i) 种硬币第 (k) 轮之后全无剩下的概率,(p_i) 表示第 (i) 种硬币正面朝上的概率,(n_i) 表示第 (i) 种硬币的个数,则 (f[i][k] = (1-p_i^k)^{n_i})

(g[i][k]) 表示第 (i) 种硬币第 (k) 轮之后至少还剩下一个的概率,显然 (g[i][k] = 1-f[i][k])

(ans[i]) 表示第 (i) 种硬币成为幸运硬币的概率,则

[ans[i] = sum_{k=0}^infty(g[i][k]-g[i][k+1])prod_{j=1,j e i}^nf[j][k] ]

后面的连乘表示除了第 (i) 种硬币外,其他的硬币在第 (k) 轮之后全无剩下的概率,(g[i][k]-g[i][k+1]) 表示第 (i) 种硬币在第 (k) 轮之后还有剩下,在第 (k+1) 轮之后全无剩下的概率,即恰好在第 (k) 轮之后成为幸运硬币的概率。如果没有减去 (g[i][k+1]) ,意义是在第 (ksim infty) 轮之后成为幸运硬币的概率,后面再算 (k+1sim infty,k+2sim infty...) 轮,会重复计算。

本题中给定的概率值在 0.4~0.6 之间,当硬币投掷次数很多时,几乎不会对后面的概率产生影响,所以选择能够不超时间空间的近似无穷大值作为 (k) 值的上界即可。


代码实现

#include <cstdio>
double f[11][1010];
double qpow(double a, int b) {
    double res = 1;
    while (b) {
        if (b & 1) res = res * a;
        b >>= 1;
        a *= a;
    }
    return res;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, ni, mxk = 1000;
        double pi;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d %lf", &ni, &pi);
            double pik = 1;
            for (int k = 0; k < mxk; k++, pik *= pi) {
                f[i][k] = qpow(1 - pik, ni);
            }
        }
        for (int i = 0; i < n; i++) {
            double ans = 0;
            for (int k = 0; k < mxk - 1; k++) {
                double tmp = 1;
                for (int j = 0; j < n; j++) {
                    if (j == i) continue;
                    tmp *= f[j][k];
                }
                ans += (f[i][k+1] - f[i][k]) * tmp;
            }
            printf("%.6f%c", ans, " 
"[i==n-1]);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kangkang-/p/12907284.html