cdcq

梦幻小鱼干

导航

【HAOI2008】下落的圆盘

原题:

 n<=1000,周长和坐标都是浮点数

 

原来认为的难题现在直接就切掉了,快乐(虽然找小错误找了很长时间)

因为已经有一定的数学知识和能力了,所以找到正解很轻松

果然数学是OI第一生产力呀

因为n不大,支持n^2,那么可以考虑其他所有圆盘对某个圆盘的覆盖情况

对于某个圆盘,以圆心为极点,水平向右为极轴建立极坐标系

接下来枚举在此圆之后落下的圆

然后用极坐标与直角坐标的转化可以得到另一个圆心的角度坐标

用余弦定理可以得到两圆交弧对应的张角

结合角度坐标得到交弧的角度坐标区间

如果区间跨过2pi或0,就拆成两个,坐标范围都转到[0,2pi]

然后求区间并,得到被覆盖的总角度

然后用弧长公式得到被覆盖的弧长

这道题一共用了3个集合知识:

极坐标,余弦定理和弧长公式

如果高四之前做的确是搞不出来的233

易错点:

1.注意判定两个半径和两圆心的连线能否构成三角形

总共有3种情况,不要漏掉

2.直角坐标转极坐标的时候注意α不是arccos(Δx/l)

arccos的范围是[0,pi],还需要判定Δy

就是这俩玩意我找了一个小时,计算几何还是细啊

 

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 double eps=1e-6;
 7 double pi=acos(-1);
 8 struct nds{double r,x,y;}a[1100];
 9 struct nd{double l,r;}q[2100];  int hd=0;
10 int n;
11 double ans=0;
12 double sqr(double x){  return x*x;}
13 double ds(int x,int y){
14     return sqrt(sqr(a[x].x-a[y].x)+sqr(a[x].y-a[y].y));
15 }
16 bool cmp(nd x,nd y){  return x.l<y.l;}
17 double cclt(int x){
18     if(a[x].r<eps)  return 0;
19     hd=0;
20     for(int i=n;i>x;--i)if(a[i].r>0 && a[x].r+a[i].r>ds(x,i) && a[x].r<a[i].r+ds(x,i)){
21         //注意判断r1<r2+l!!!
22         if(ds(x,i)+a[x].r<a[i].r)  return 0;
23         if(ds(x,i)<eps)  continue;
24         double th=acos((sqr(a[x].r)+sqr(ds(x,i))-sqr(a[i].r))/(2.0*a[x].r*ds(x,i)));
25         double af=acos((a[i].x-a[x].x)/ds(x,i));
26         if(a[i].y<a[x].y)  af=2.0*pi-af;
27         //注意,直接对Δx求出的α范围是0到pi
28         if(af-th<0){
29             q[++hd]=(nd){0,af+th};
30             q[++hd]=(nd){af-th+2.0*pi,2.0*pi};
31         }
32         else if(af+th>2*pi){
33             q[++hd]=(nd){af-th,2.0*pi};
34             q[++hd]=(nd){0,af+th-2.0*pi};
35         }
36         else  q[++hd]=(nd){af-th,af+th};
37     }
38     sort(q+1,q+hd+1,cmp);
39     double l=0,r=0;
40     double bwl=0;
41     for(int i=1;i<=hd;++i){
42         if(q[i].l<r)  r=max(r,q[i].r);
43         else{
44             bwl+=r-l;
45             l=q[i].l,r=q[i].r;
46         }
47     }
48     bwl+=r-l;
49     return (2.0*pi-bwl)*a[x].r;
50 }
51 int main(){
52     cin>>n;
53     for(int i=1;i<=n;++i){
54         scanf("%lf%lf%lf",&a[i].r,&a[i].x,&a[i].y);
55     }
56     for(int i=n;i>=1;--i){
57         ans+=cclt(i);
58     }
59     printf("%.3lf\n",ans);
60     return 0;
61 }
View Code

 

posted on 2020-04-07 23:23  cdcq  阅读(148)  评论(0编辑  收藏  举报