BZOJ1043 [HAOI2008]下落的圆盘

时间:2020-12-26 00:54:15

每个圆盘只会受到后边的圆盘的影响

所以算一下每个圆盘和后边的圆盘相交的圆心角,然后求个并即可

可以用余弦定理

复杂度n^2 log n

注意特判没有交-_-

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 1010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
const double pi=acos(-1);
struct cir{
	double x;
	double y;
	double r;
};
struct itv{
	double l;
	double r;
	itv(){
		
	}
	itv(double _l,double _r){
		l=_l;
		r=_r;
	}
	friend bool operator <(itv x,itv y){
		return x.l<y.l;
	}
};
itv a[MAXN*2];
cir c[MAXN];
double ans;
int tot;
int n;
double sq(double x){
	return x*x;
}
double dis(cir x,cir y){
	return sqrt(sq(x.x-y.x)+sq(x.y-y.y));
}
double cal(){
	int i;
	double re=0;
	sort(a+1,a+tot+1);
	double r=-pi;
	for(i=1;i<=tot;i++){
		if(a[i].l>r){
			re+=a[i].l-r;
		}
		r=max(r,a[i].r);
	}
	re+=pi-r;
	return re;
}
int main(){
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%lf%lf%lf",&c[i].r,&c[i].x,&c[i].y);
	}
	for(i=n;i;i--){
		bool flag=0;
		tot=0;
		for(j=i+1;j<=n;j++){
			if(dis(c[i],c[j])<c[i].r+c[j].r){
				if(dis(c[i],c[j])+c[i].r<=c[j].r){
					flag=1;
					break;
				}else if(dis(c[i],c[j])+c[j].r<=c[i].r){
					
				}else{
					double angf=acos((sq(c[i].r)+sq(dis(c[i],c[j]))-sq(c[j].r))/(2*c[i].r*dis(c[i],c[j])));
					double ang=atan2(c[j].y-c[i].y,c[j].x-c[i].x);
					double l=ang-angf,r=ang+angf;
					if(l<-pi){
						a[++tot]=itv(l+2*pi,pi);
						a[++tot]=itv(-pi,r);
					}else if(r>pi){
						a[++tot]=itv(l,pi);
						a[++tot]=itv(-pi,r-2*pi);
					}else{
						a[++tot]=itv(l,r);
					}
				}
			}
		}
		if(flag){
			continue ;
		}
		ans+=cal()*c[i].r;
	}
	printf("%.3lf\n",ans);
	return 0;
}

/*

*/