[bzoj1043][HAOI2008]下落的圆盘【计算几何】
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=1043
【题解】
考虑每个圆对答案的贡献,对于每个圆,枚举之后下落的圆盘,求出被覆盖的区间相对于X轴正方向的夹角的弧度值,然后排序,求出没被覆盖的弧度区间即可。
时间复杂度
tips:c++的反三角函数可能由于精度问题返回nan。
/* --------------
user Vanisher
problem bzoj-1043
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 1010
# define eps 1e-10
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct point{
double x,y;
}c[N];
struct node{
double l,r;
}q[N*2];
double pi=acos(-1.0),r[N],ans;
double sqr(double x){return x*x;}
int num,n;
double dis(point x, point y){
return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
double cosf(double a, double b, double c){
double now=(sqr(a)+sqr(b)-sqr(c))/(2*a*b);
if (now<=-1) now+=eps;
if (now>=1) now-=eps;
return now;
}
bool cmp(node x, node y){
return x.l<y.l;
}
void join(double l, double r){
q[++num]=(node){l,r};
}
int main(){
n=read();
for (int i=1; i<=n; i++)
scanf("%lf%lf%lf",&r[i],&c[i].x,&c[i].y);
for (int i=1; i<=n; i++){
num=0;
bool flag=false;
for (int j=i+1; j<=n; j++){
double d=dis(c[i],c[j]),tmp,o;
if (d+r[i]<=r[j]){
flag=true; break;
}
if (d+r[j]<=r[i]) continue;
if (d>=r[i]+r[j]) continue;
tmp=acos(cosf(r[i],d,r[j]));
o=acos(cosf(r[i],d,dis((point){c[i].x,c[i].y+r[i]},c[j])));
if (c[i].x>c[j].x) o=2*pi-o;
double l=o-tmp, r=o+tmp;
if (l<0){
join(l+2*pi,2*pi);
join(0,r);
}
else if (r>2*pi){
join(l,2*pi);
join(0,r-2*pi);
}
else join(l,r);
}
if (flag) continue;
sort(q+1,q+num+1,cmp);
double nowr=0,now=0;
for (int j=1; j<=num; j++){
now=now+max(q[j].l-nowr,0.0);
nowr=max(q[j].r,nowr);
}
now=now+2*pi-nowr;
ans=ans+now*r[i];
}
printf("%.3lf\n",ans);
return 0;
}