bzoj1043: [HAOI2008]下落的圆盘

时间:2022-03-08 03:50:46

传送门
看到数据范围不大,暴力走起。
枚举每一个圆,如果被完全覆盖直接退出。
否则如果被覆盖掉一部分就求出覆盖区间。
然后就是sb的区间覆盖问题了。

#include<cmath> 
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
using namespace std;
int n,top;
double ans,r[1005],x[1005],y[1005];
struct line{double l,r;}q[2005];
bool cmp(line a,line b){
    return a.l<b.l;
}
double sqr(double x){return x*x;}
double dis(int a,int b){
    return sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b]));
}
bool init(int a,int b){
    return r[a]>=r[b]+dis(a,b);
}
void add(int a,int b){
    double d,t,st,l;
    d=dis(a,b);
    t=(sqr(r[a])-sqr(r[b])+sqr(d))/(2*d);//余弦定理
    st=atan2(x[a]-x[b],y[a]-y[b]);
    l=acos(t/r[a]);
    q[++top]=(line){st-l,st+l};
}
double cal(int x){
    for (int i=x+1;i<=n;i++)
        if (init(i,x)) return 0;
    top=0;
    for (int i=x+1;i<=n;i++)
        if (!init(x,i)&&r[x]+r[i]>=dis(x,i))
            add(x,i);
    for (int i=1;i<=top;i++){
        if (q[i].l<0) q[i].l+=2*pi;
        if (q[i].r<0) q[i].r+=2*pi;
        if (q[i].l>q[i].r){
            q[++top]=(line){0,q[i].r};
            q[i].r=2*pi;
        }
    }
    sort(q+1,q+top+1,cmp);
    double tmp=0,now=0;
    for (int i=1;i<=top;i++)
        if (q[i].l>now){
            tmp+=q[i].l-now;
            now=q[i].r;
        }
        else now=max(now,q[i].r);
    tmp+=2*pi-now;
    return r[x]*tmp;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
    for (int i=1;i<=n;i++)
        ans+=cal(i);
    printf("%.3lf",ans);
}