题目传送门:Mocha and Railgun
题目大意
- 给定一个圆和严格位于圆内的一点 。
- Mocha 会从点 向任意角度发射一个长度为 的电磁炮。
- 电磁炮底边的中点为点 且两端位于圆内。
- 询问单次发射能摧毁的最大圆弧长。
- 询问若干次单次发射能摧毁的最大圆弧长。
- 计算误差不超过。
那么,问题来了:
什么样的情况下能够摧毁的弧长最大?
上图!
根据中学数学我们知道,想要圆弧更长,那么它对应的弦就得更长。那么,对于线段,我们需要令其对应的弦最长。做线段,令其垂直于电磁炮的边界。这样我们就得到了一个三角形:其中易得的长度为,是固定的,那么想让最长就等价于找到最长的了。不难得知当的位置和固定时,当线段或的延长线经过时最长。
那么就可以开始愉快的分类讨论了!
根据中学数学知识我们知道弧长,即半径乘其对应的圆心角。 那么我们不妨设Q到O的距离为,即。
- 当的延长线经过时:
在这种情况下,,我们可以用来求得其圆心角。由图知,。利用反三角函数就可求得圆心角。
2. 当经过时:
在这种情况下,,我们可以用来求得其圆心角。由图知,。利用反三角函数就可求得圆心角。
那么大概思路就是这样了。当然有一些小细节别忘记了:
- 计算误差不超过。
- 注意有多组输入输出,输出答案时需要换行!(就是因为它我们贡献了一发罚时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;
}