hdu 6158 The Designer

来源:互联网 发布:淘宝女童秋装 编辑:程序博客网 时间:2024/05/16 23:42

题解

比赛之后有大佬说这题可以用圆的反演来做,学习了一下。

以两个大圆的切点为反演中心,任取一个反演半径,两个大圆会变成两条平行线。再考虑小圆的反演,由于相切的性质不变,小圆的反演圆就是一列夹在平行线中间的小圆。

示意图:

圆的反演

当然这样还是 O(n) 的,但是看题目里的图就知道小圆会越来越小,小到一定程度以后直接不考虑就行了。

代码

#include <bits/stdc++.h>using namespace std;typedef long double ld;const ld IR2=100;const ld PI=3.141592653589793238462643383279502884197169399375105820974944592307816L;struct Point {    ld x,y;    Point(ld _x=0,ld _y=0):x(_x),y(_y) {}    Point operator +(const Point &R) {        return Point(R.x+x,R.y+y);    }    Point operator -(const Point &R) {        return Point(R.x-x,R.y-y);    }    ld operator *(const Point &R) {        return R.x*x+R.y*y;    }    Point operator *(const ld &R) {        return Point(x*R,y*R);    }    void print() {        double o1=x,o2=y;        cout<<o1<<" "<<o2<<"\n";    }};#define sqr(x) ((x)*(x))ld inv_circle(Point O,Point C,ld r){    return IR2*r/(sqr(O-C)-sqr(r));}int main(){    int T;    scanf("%d",&T);    Point O(0,0);    while (T--) {        double t1,t2;        scanf("%lf%lf",&t1,&t2);        if (t1>t2) swap(t1,t2);        ld r=t1,R=t2;        int n;        scanf("%d",&n);        Point P(0.5*IR2/R,0);        Point Q(0.5*IR2/r,0);        ld L=Q.x-P.x;        Point o((P+Q)*0.5);        ld ans=0;        if (n%2==0) {            Point C(o.x,o.y+(n/2)*L);            ld rr=inv_circle(O,C,L*0.5);            ans+=PI*rr*rr;        }        for (int i=1;i+i-1<=n;i++) {            Point C(o.x,o.y+(i-1)*L);            ld rr=inv_circle(O,C,L*0.5);            ld area=PI*rr*rr;            if (area<1e-12) break;            ans+=area;            if (i>1) ans+=area;        }        double out=ans;        printf("%.5f\n",out);    }    return 0;}

尾巴

大佬不愿意透露id,鸣谢csust?

原创粉丝点击