2020 ICPC南京 F - 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;
}