题解 | #F. 一个经典概率问题(提供一个好想好实现不用积分的方法)#
一个经典概率问题
https://ac.nowcoder.com/acm/contest/11215/F
F. 一个经典概率问题
思路
这里提供一个好想好实现不用积分的方法
假设把圆分成两个区域,一个圆心为 半径为 的圆,一个是半径为 中间的空心是半径 的圆的一个环,两者面积是 和 ,那么B的选法落在环上概率比落在圆上的概率肯定更大,那么这样得到的弦长就会比以半径中点形成的弦长小(因为随着落点远离圆心形成的弦长是个递减过程)两者之比是 。所以最终比界限小弦长数量应该更多的。
而L的选法是随机在一条半径上选一点,弦长与哪条半径上无关,只与离圆心的距离有关,于是我们就可以得出L方法形成的弦长落在以半径中点形成弦长两端的概率相等,两者之比是 。
于是最终我们只需要比较弦长,落在以半径中点形成弦长的两端那边多即可。
不过需要注意的是,因为L的选法是均分,所以概率上来讲是有可能导致落在更小区域的更多,所以不能直接这样判断,需要给定一个值偏离太多才判定为B的选法(博主自己就是忘记设定偏离值将部分L错判为B).
代码
#include <bits/stdc++.h>
using namespace std;
const double N = 1e5;
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
double c = 1.0 / N;
double r = c * 5e4; // 也可以直接用0.5
double mid = 2.0 * sqrt(1 - r * r); // 以半径中点形成的弦长
int n;
cin >> n;
int sum1 = 0, sum2 = 0;
for(int i = 1; i <= n; i ++){
double x; cin >> x;
if(x - mid > 1e-6) sum2 ++;
else sum1 ++;
}
if(sum2 + 10000 < sum1) cout << "B"; // 记得要设定偏离值
else cout << "L";
return 0;
}
法二思路
从别的博客那里学了一手法二,通过积分的方法可以确定,L方法 长度的平均值为 , B方法平均值为 。将给出的弦长换算出 长,求出平均值看更接近哪一个
法二代码
#include <bits/stdc++.h>
using namespace std;
const double N = 1e6;
/*
L方法每次在一条半径上随机选点p, 那么op的平均长度就是0.5
B方法积分求解后平均长度是2/3
算出平均值后看与那个更接近
*/
int main(){
int n;
cin >> n;
double sum = 0;
for(int i = 1; i <= n; i ++){
double x; cin >> x; x /= 2.0;
sum += sqrt(1 - x * x);
}
sum /= (double)n;
double x1 = fabs(sum - 0.5);
double x2 = fabs(sum - 0.6666666);
if(x1 < x2) cout << "L";
else cout << "B";
return 0;
}