BZOJ1043: [HAOI2008]下落的圆盘

32 篇文章 0 订阅
7 篇文章 0 订阅

求红线总长可以用每个圆的周长减去被覆盖的部分
对每个圆i,枚举 j>i j > i 计算圆j覆盖了圆i的长度
若i和j相离/相切或i包含j不考虑
若i被j包含就被完全覆盖
否则是相交的情况如图
这里写图片描述
圆A和圆B交与C,D,可以算出AE,CE的长度,用余弦定理可以算得cosCAE,用acos,atan2可以算得A被覆盖的一个弧度区间,把所有覆盖的区间求出来后就变成了一个区间覆盖问题

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 1100;
const double pi = acos(-1);
const double eps = 1e-9;
const double sqr(const double x){return x*x;}

int n;
struct node
{
    double x,y,r;
}a[maxn];
struct interval
{
    double l,r;
    friend inline bool operator <(const interval x,const interval y)
    {
        return x.l<y.l;
    }
}t[maxn]; int tp;
double ans;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].r,&a[i].x,&a[i].y);

    for(int i=1;i<=n;i++)
    {
        tp=0; bool fl=true;
        for(int j=i+1;j<=n;j++)
        {
            double dis=sqrt(sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y));
            if(dis>a[i].r+a[j].r-eps) continue;
            if(dis<a[i].r-a[j].r+eps) continue;
            if(dis<a[j].r-a[i].r+eps) { fl=false;break; }

            double dec=acos((sqr(a[i].r)+sqr(dis)-sqr(a[j].r))/(2.0*a[i].r*dis));
            double mid=atan2(a[j].y-a[i].y,a[j].x-a[i].x);
            double l=mid-dec,r=mid+dec;
            if(r>pi) t[++tp]=(interval){-pi,-pi+r-pi},r=pi;
            if(l<-pi) t[++tp]=(interval){pi-(-pi-l),pi},l=-pi;
            t[++tp]=(interval){l,r};
        }
        if(!fl) continue;
        sort(t+1,t+tp+1);
        double las=-pi,sum=0;
        for(int j=1;j<=tp;j++)
        {
            if(las<t[j].l) sum+=t[j].l-las;
            las=max(las,t[j].r);
        }
        sum+=pi-las;
        ans+=sum*a[i].r;
    }
    printf("%.3lf\n",ans);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值