UVa 11346 Probability (积分)

题目

题目大意

\([-a, a] × [-b, b]\)区域内随机取一个点\(P\), 求以\((0, 0)\)\(P\)为对角线的长方形面积大于\(S\)的概率(\(a, b > 0\), \(S ≥ 0\))。例如\(a = 10\), \(b = 5\), \(S = 20\), 答案为\(23.35\%\)

题解

根据对称性, 只需要考虑\([0, a] × [0, b]\)区域取点即可。设点的横纵坐标为\(x\), \(y\), 面积大于\(S\), 即\(xy > S\)\(xy = S\)是一条双曲线, 所求概率就是\([0, a] × [0, b]\)中处于双曲线上面的部分。为了方便, 求双曲线下面的面积, 然后用总面积来减。

设双曲线和区域\([0, a] × [0, b]\)左边交点的坐标为\((\frac{S}{b}, b)\), 因此积分就是:

\[S + S\int_{\frac{S}{b}}^{a}\frac{1}{x}dx \]

根据高中所学数学知识, 得到\(\frac{1}{x}\)的原函数是\(ln\ x\), 因此积分部分就是\(ln\ a - ln\ \frac{S}{b} = ln\ \frac{ab}{S}\)。设面积为\(m\), 则答案为\(m - S - \frac{S\ ln \frac{m}{S}}{m}\)

得到以上答案的前提是双曲线与所求区域相交, 如果\(S > ab\), 则概率应为\(0\); 而如果\(S\)太接近\(0\), 概率应直接返回\(1\), 否则计算会出错。

代码

#include <cstdio>
#include <cmath>
#include <algorithm>
int main(int argc, char const *argv[]) {
  register int cases;
  register double a, b, s;
  scanf("%d", &cases);
  while (cases--) {
    scanf("%lf %lf %lf", &a, &b, &s);
    register double r = std::min(s / b, a);
    register double ans = r * b + log(a) * s;
    if (fabs(s) > 1e-9) ans = ans - log(r) * s;
    register double p = 1 - ans / (a * b);
    printf("%.6lf%%\n",  fabs(p * 100));
  }
  return 0;
}
posted @ 2018-09-29 10:44  Acenaphthene  阅读(159)  评论(0编辑  收藏  举报