P2510 [HAOI2008]下落的圆盘

传送门

首先考虑两个圆覆盖的情况,我们可以求出圆心与交点连线 $A$ 的极角

具体就是求出两圆心连线 $B$ 极角加上余弦定理加反余弦求出 $A,B$ 之间夹角 ,然后覆盖了多少就可以得出

但是多个圆覆盖会重复算,所以离线枚举后面的圆,然后把覆盖的区间按极角排序做一遍类似线段覆盖的操作就行了

区间覆盖的时候注意极角可以会算出负数和大于 $2\pi$ 的情况

思路倒挺简单,计算几何实现起来反正就是一堆细节

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef double db;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const db pi=acos(-1.0),pi2=pi*2,eps=1e-12;
const int N=4007;
int n;
inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; }
struct Poi {
    db x,y;
    Poi (db a=0,db b=0) { x=a,y=b; }
    inline Poi operator - (const Poi &tmp) const {
        return Poi(x-tmp.x,y-tmp.y);
    }
};
inline db Len(Poi A) { return sqrt(A.x*A.x+A.y*A.y); }
inline db angle(Poi A) { return atan2(A.y,A.x); }
struct Circ {
    Poi O; db r;
    Circ (Poi a=Poi(0,0),db b=0) { O=a,r=b; }
}C[N];
struct dat {
    db ang; int type;
    dat (db a=0,int b=0) { ang=a,type=b; }
    inline bool operator < (const dat &tmp) const {
        return ang<tmp.ang;
    }
}D[N];
db work(int p)
{
    db res=0; int tot=0,cnt=0;
    for(int i=p+1;i<=n;i++)
    {
        db dis=Len(C[i].O-C[p].O);
        if( C[p].r+dis<=C[i].r ) return 0;//p被完全覆盖
        if( dis>=C[p].r+C[i].r || C[i].r+dis<=C[p].r ) continue;//p没被覆盖,记得可能 i 在 p 里面
        db alp=acos( (dis*dis+C[p].r*C[p].r-C[i].r*C[i].r)/(2*dis*C[p].r) ),k=angle(C[i].O-C[p].O);
        db l=k-alp,r=k+alp;//两个交点的极角
        if(dcmp(l)<0&&dcmp(r)<0) { D[++tot]=dat(l+pi2,1); D[++tot]=dat(r+pi2,-1); continue; }
        if(dcmp(l)>=0&&r<=pi2) { D[++tot]=dat(l,1); D[++tot]=dat(r,-1); continue; }
        if(dcmp(l)<0&&dcmp(r)>=0)
        {
            D[++tot]=dat(l+pi2,1); D[++tot]=dat(pi2,-1);
            D[++tot]=dat(0,1); D[++tot]=dat(r,-1);
        }
        if(dcmp(l)>=0&&r>pi2)
        {
            D[++tot]=dat(0,1); D[++tot]=dat(r-pi2,-1);
            D[++tot]=dat(l,1); D[++tot]=dat(pi2,-1);
        }
    }
    sort(D+1,D+tot+1);
    for(int i=1;i<=tot;i++)
    {
        if(D[i].type==1&&!cnt) res+=D[i].ang-D[i-1].ang;//线段覆盖
        cnt+=D[i].type;
    }
    res+=pi2-D[tot].ang;
    return C[p].r*res;
}
int main()
{
    n=read(); db a,b,c,ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf%lf",&a,&b,&c);
        C[i]=Circ( Poi(b,c) , a );
    }
    for(int i=1;i<=n;i++) ans+=work(i);
    printf("%.3f\n",ans);
    return 0;
}

 

posted @ 2019-08-31 12:56  LLTYYC  阅读(184)  评论(0编辑  收藏  举报