2020 ICPC南京 F - Fireworks(概率、三分)

Fireworks

题目大意:

花费n时间做一个烟花,释放已做好的所有烟花花费m时间,每个烟花是完美的概率为$ p \times 10^{-4}$,问在最优策略下成功释放第一个烟花的最小期望时间。

思路:

不妨假设每做完k个烟花后释放一次,这一轮的时间开销为\(k * n + m\),在一轮中完美烟花的数量X满足二项分布,即X~b(k, p),在一轮中至少有1个烟花是完美的概率为:

$P_{1} = $$P {X \geq 1} = (1 - (1- p)^k)$

即为每一轮成功的概率。

现在的关键是求最优在第几轮成功,显然是一个几何分布的问题,设Y为首次出现完美烟花经过的轮数,则Y~GE(\(P_{1}\))。

结合几何分布的期望公式:\(E(\xi) = \frac{1}{p}\)

我们可以得到\(\frac{1}{P_{1}}\)即为出现完美烟花轮数的期望。(几何分布期望的意义:期望\(E(\xi)\)次实验后实验首次成功)

那么题目要求的最小期望时间 \(=\) 期望轮数 \(\times\) 每一轮花费的时间,即为:

\(\frac{k * n + m}{1 - (1- p)^k}\)

对该式打表可以看出为一个双调函数(或者大胆下结论),使用三分法可以求得最小期望时间。

Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PI;
const double eps = 1e-6;
const int N = 200010;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007; //998244353
LL powmod(LL a, LL b) { LL res = 1; a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1)res = res * a % mod; a = a * a % mod; }return res; }

long double poww(long double a, LL b) {
    long double res = 1;
    for (; b; b >>= 1, a *= a) 
        if (b & 1) res *= a;
    return res;
}

long double Q, f1, f2, ans;
LL n, m, p; 

long double f(LL k) {
    return (k * n + m) / (1 - poww(Q, k));
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T--) {
        ans = 1000000000000.0;
        cin >> n >> m >> p;
        Q = 1 - p * 0.0001;
        LL lf = 1, rt = INF;
        while (lf < rt) {
            LL mid1 = (2 * lf + rt) / 3;
            LL mid2 = (lf + 2 * rt) / 3;
            f1 = f(mid1);
            f2 = f(mid2);
            ans = min(ans, min(f1, f2));
            if (f1 > f2) 
                lf = mid1 + 1;
            else 
                rt = mid2;
        }
        cout << fixed << setprecision(8) << ans << endl;
    }
    return 0;
}

https://baike.baidu.com/item/定比分点公式

posted @ 2021-01-27 16:18  Nepenthe8  阅读(185)  评论(0编辑  收藏  举报