BZOJ1043: [HAOI2008]下落的圆盘
BZOJ1043: [HAOI2008]下落的圆盘
https://lydsy.com/JudgeOnline/problem.php?id=1043
分析:
- 这题我写了\(2k\)..
- 先是\(O(n^2)\)枚举覆盖的圆盘,求出被覆盖的弧度范围\([l,r]\)。
- 这个我们用余弦定理求一下即可。
- 注意\(atan2(x,y)\)求的是\((x,y)\)的夹角。
- 求出来之后排序+扫描线求哪些是被覆盖过的。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;
typedef double f2;
#define N 1050
#define eps 1e-8
const f2 pi = acos(-1);
f2 pf(f2 x) {return x*x;}
struct Point {
f2 x,y;
Point() {}
Point(f2 x_,f2 y_) {x=x_,y=y_;}
Point operator + (const Point &p) const {return Point(x+p.x,y+p.y);}
Point operator - (const Point &p) const {return Point(x-p.x,y-p.y);}
Point operator * (f2 rate) const {return Point(x*rate,y*rate);}
};
f2 cross(const Point &p1,const Point &p2) {return p1.x*p2.y-p1.y*p2.x;}
f2 dis(const Point &p1,const Point &p2) {return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));}
struct Circle {
Point p; f2 r;
}a[N];
struct A {
f2 x,v;
bool operator < (const A &u) const {return x<u.x;}
}pos[N<<1];
int n; f2 ans;
int main() {
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++) {
scanf("%lf%lf%lf",&a[i].r,&a[i].p.x,&a[i].p.y);
}
for(i=1;i<=n;i++) {
int m=0,now=0;
for(j=i+1;j<=n;j++) {
f2 x=a[i].r,y=a[j].r,z=dis(a[i].p,a[j].p);
if(x+z<=y) {
now=m=0; ans-=2*pi*a[i].r; break;
}
if(x+y<z||x+z<y||y+z<x) continue;
f2 cy=acos((pf(x)+pf(z)-pf(y))/(2*x*z));
f2 ct=atan2(a[j].p.x-a[i].p.x,a[j].p.y-a[i].p.y);
f2 l=0.5*pi-ct-cy,r=l+2*cy;
while(l<0) l+=2*pi;
while(l>2*pi) l-=2*pi;
while(r<0) r+=2*pi;
while(r>2*pi) r-=2*pi;
pos[++m]=(A){l,1};
pos[++m]=(A){r,-1};
if(l>r) now++;
}
pos[++m]=(A){2*pi,0};
sort(pos+1,pos+m+1);
ans+=2*pi*a[i].r;
for(j=1;j<=m;j++) {
if(now>0) {
ans-=(pos[j].x-pos[j-1].x)*a[i].r;
}
now+=pos[j].v;
}
}
printf("%.3f\n",ans);
}