zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    60     return 0;
    61 }
    View Code
  • 相关阅读:
    离散数学期中复习
    计算机组成原理实验_算术逻辑运算器的实现
    数值分析第一章插值方法
    数值分析绪论
    数值分析第三章 常微分方程的差分方法
    数值分析第二章 数值积分
    数据库删除信息后,再次加入信息ID不再从1开始的解决办法
    Codeforces Round #670 (Div. 2)(树的重心,dfs求子树大小)
    Codeforces Round #670 (Div. 2)B. Maximum Product(5个数乘积最大)
    Codeforces Round #668 (Div. 2)A->C
  • 原文地址:https://www.cnblogs.com/cdcq/p/12657051.html
Copyright © 2011-2022 走看看