[HAOI2008]下落的圆盘
直接暴力O(n^2)枚举 每一个圆盘和其后面落下的圆盘
i 当前枚举的圆 j i之后的圆
然后利用atan2函数求出(x[j]-x[i],y[j]-y[i])向量与x轴的夹角
再根据d(圆心之间距离)、r[i]、r[j]余弦定理求出向量可以向上下扩展的角度
用贪心线段覆盖...
枚举的时候有几种特殊情况:
1.两个圆相离
2.i在j内
3.j在i内
4.斜率不存在的情况不用考虑,atan2函数就行了
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define dd double
using namespace std;
const int N=1006;
const dd pai=acos(-1.0);
struct son
{
dd l,r;
bool friend operator < (son a,son b)
{
if(a.l==b.l)
return a.r<b.r;
return a.l<b.l;
}
}ji[N*10];
int con;
int n;
dd r[N],x[N],y[N];
inline dd dis(dd x3,dd y3,dd x4,dd y4)
{
return sqrt( (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3) );
}
dd check()
{
sort(ji+1,ji+1+con);
dd ans=0,las=-pai;
for(int i=1;i<=con;++i)
{
if(ji[i].l<las)
{
if(ji[i].r>las)
ans+=(ji[i].r-las);
}
else
{
ans+=(ji[i].r-ji[i].l);
}
if(las<ji[i].r)
las=ji[i].r;
}
return ans;
}
dd work()
{
dd ce1,ce2,d,ans=0,temp,sh,xi;
for(int i=1;i<=n;++i)
{
con=0;
for(int j=i+1;j<=n;++j)
{
d=dis(x[i],y[i],x[j],y[j]);
if(d>r[i]+r[j])//i和j相离
continue;
if(d+r[i]<r[j])//i整个被覆盖
{
ji[++con]=(son){-pai,pai};
break;
}
if(d+r[j]<r[i])//j在i中间
continue;
/*if(x[j]==x[i])
ce1=(y[j]-y[i]>0?pai/2.0:-pai/2.0);//直角 .... (还是别判断了...容易wa)
else*/
ce1=atan2( (x[j]-x[i]),(y[j]-y[i]) );
ce2=acos( (r[i]*r[i]+d*d-r[j]*r[j])/(2*r[i]*d) );
sh=ce1+ce2;xi=ce1-ce2;
if(sh>pai)
ji[++con]=(son){ -pai,sh-2*pai },sh=pai;
if(xi<-pai)
ji[++con]=(son){ xi+2*pai,pai },xi=-pai;
ji[++con]=(son){ xi,sh };
}
temp=check();
//printf("temp=%lf\n",temp);
ans+=((2.0*pai-temp)*r[i]);
}
return ans;
}
int main(){
//freopen("in.in","r",stdin);
//freopen("disc.in","r",stdin);
//freopen("disc.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
printf("%.3lf",work());
}