[bzoj1043][HAOI2008]下落的圆盘【计算几何】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=1043
【题解】
  考虑每个圆对答案的贡献,对于每个圆,枚举之后下落的圆盘,求出被覆盖的区间相对于X轴正方向的夹角的弧度值,然后排序,求出没被覆盖的弧度区间即可。
  时间复杂度O(N2logN)
  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;
}
posted @ 2018-04-01 20:57  Vanisher  阅读(84)  评论(0编辑  收藏  举报