链接:https://www.nowcoder.com/acm/contest/205/F
来源:牛客网
题目描述
终于活成了自己讨厌的样子。
对于每个关卡,原本会以p的概率掉衣服。如果双倍概率,那么会以的概率掉衣服。
经过统计,栗子米抽了n次一倍掉率的关卡,掉了a次衣服,抽了m次二倍掉率的关卡,掉了b次衣服。能不能告诉栗子米,暖婊真实的掉率最可能是多少。你可以认为在做统计之前,p为一个[0,1]之间的均匀分布。
输入描述:
第一行一个整数T(T≤ 105),表示数据组数。 每组数据第一行四个整数n,m,a,b(1≤ n,m≤ 109,0≤ a≤ n,0≤ b≤ m)。
输出描述:
对于每组数据,输出一个0到1之间的实数,表示最有可能的概率,保证这个最有可能的概率是良好并且唯一定义的,如果相对误差或者绝对误差在10-9之内那么你的答案被认为是正确的。
示例1
输入
复制
5 3 3 1 2 3 3 0 0 3 3 3 3 5 5 5 0 7 9 2 6
输出
复制
0.3333333333 0.0000000000 1.0000000000 0.2500000000 0.3253523925
已知以单倍概率抽n次,掉a件,双倍概率抽m次,掉b件。
考虑当概率为p时,以上事件发生的概率,设其为f,那么可以知道f越大,概率为p的可能就越大。
如何计算f呢?
当
单倍掉率中:抽中a次的概率为,抽不中(n-a)次的概率为
,在n次中有a次抽中的情况数有
个;
双倍掉率中:抽中b次的概率为,抽不中的(m-b)次的概率为
,在m次中有b次抽中的情况数有
个。
那么有:
对f取对数,再求导,可以得到
分母在 时非负,通过分子判断极大值点即可,解一元二次方程就行。
当
一定有 且
,此时直接计算
即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-10;
int T;
double n, m, a, b;
double getX(double a, double b, double c) {
double delta = b * b - 4 * a * c;
if (delta <= eps) return 0.5;
delta = sqrt(delta);
double ans = (-b - delta) / (2 * a);
return min(ans, 0.5);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%lf%lf%lf%lf", &n, &m, &a, &b);
double ans;
if (b == m && a * 2 >= n) ans = a / n;
else ans = getX(2.0*(n+m), -2*a-b-n-2*m, a+b);
printf("%.10f\n", ans);
}
return 0;
}