题目传送门:Mocha and Railgun

题目大意

  • 给定一个圆和严格位于圆内的一点 PP
  • Mocha 会从点 PP 向任意角度发射一个长度为 2d2d 的电磁炮。
  • 电磁炮底边的中点为点 PP 且两端位于圆内。
  • 询问单次发射能摧毁的最大圆弧长。
  • 询问若干次单次发射能摧毁的最大圆弧长。
  • 计算误差不超过10610^{-6}

    那么,问题来了:

什么样的情况下能够摧毁的弧长最大?

上图!


  根据中学数学我们知道,想要圆弧更长,那么它对应的弦就得更长。那么,对于线段ABAB,我们需要令其对应的弦cc最长。做线段bb,令其垂直于电磁炮的边界。这样我们就得到了一个三角形:其中易得bb的长度为2d2d,是固定的,那么想让cc最长就等价于找到最长的aa了。不难得知当QQ的位置和dd固定时,当线段ABABABAB的延长线经过OOaa最长。

那么就可以开始愉快的分类讨论了!

  根据中学数学知识我们知道弧长L=α×rL=\alpha \times r,即半径乘其对应的圆心角。 那么我们不妨设Q到O的距离为lOQl_{OQ},即xQ2+yQ2\sqrt{x_{Q}^{2}+y_{Q}^{2} }

  1. ABAB的延长线经过OO时:

  在这种情况下,lOQ>dl_{OQ}> d,我们可以用αβ\angle \alpha - \angle\beta 来求得其圆心角。由图知cosα=lOQdrcos\angle \alpha=\frac{l_{OQ}-d}{r} cosβ=lOQ+drcos\angle \beta=\frac{l_{OQ}+d}{r}。利用反三角函数就可求得圆心角αβ\angle \alpha - \angle\beta

 2. 当ABAB经过OO时:


  在这种情况下,lOQdl_{OQ}\le d,我们可以用παβ\pi -\angle \alpha - \angle\beta 来求得其圆心角。由图知cosα=dlOQrcos\angle \alpha=\frac{d-l_{OQ}}{r} cosβ=d+lOQrcos\angle \beta=\frac{d+l_{OQ}}{r}。利用反三角函数就可求得圆心角παβ\pi -\angle \alpha - \angle\beta

  那么大概思路就是这样了。当然有一些小细节别忘记了:

  • 计算误差不超过10610^{-6}
  • 注意有多组输入输出,输出答案时需要换行!(就是因为它我们贡献了一发罚时TAT)

    最后献上参考代码~
#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
#define debug(x) cout<<#x<<":"<<x
#define pi acos(-1)//注意常数π哦
using namespace std;

int t;//数据组数
double r;//半径
double xx,yy,d;//Q的坐标和d
double len,ans;//O到Q的距离和最终的答案

void solve(){
    scanf("%lf",&r);
    scanf("%lf",&xx),scanf("%lf",&yy),scanf("%lf",&d);
    len=sqrt(xx*xx+yy*yy);//计算O到Q的距离
    if(len>d){//分类讨论
        ans=r*(acos((len-d)/r)-acos((len+d)/r));
    }else{
        ans=r*(pi-acos((d-len)/r)-acos((len+d)/r));
    }
    printf("%.12lf\n",ans);//换行别忘记咯
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    scanf("%d",&t);
    while(t--) solve();
    return 0;
}

  感谢观看!