传送门
题解:
这道题 n n n 很大,但是这不是问题,是个人都知道在面积足够小的时候直接break掉,所以问题在于怎么求出下一个圆。
直接求显然很麻烦,考虑反演,以两个大圆的切点为反演中心,两个大圆反演后显然就是两条直线,而那些小圆就是夹在直线中的一个个等圆,直接反演回去得到半径即可。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const
using std::cerr;
using std::cout;
cs db eps=1e-14;
cs db PI=acos(-1);
db R,r1,r2;
int sign(db x){return x<-eps?-1:(x>eps?1:0);}
struct Pnt{
db x,y;Pnt(){}Pnt(db _x,db _y):x(_x),y(_y){}
friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y+b.y);}
friend Pnt operator*(cs Pnt &a,cs db b){return Pnt(a.x*b,a.y*b);}
friend Pnt operator/(cs Pnt &a,cs db b){return Pnt(a.x/b,a.y/b);}
inline db len()cs{return sqrt(x*x+y*y);}
};
inline db sqr(db x){return x*x;}
inline db dis(cs Pnt &a,cs Pnt &b){
return (a-b).len();
}
inline db get_r(cs Pnt &o,cs db &r){
return r/(sqr(o.len())-sqr(r))*sqr(R);
}
void Main(){
R=20;int T;scanf("%d",&T);
while(T--){
scanf("%lf%lf",&r1,&r2);
if(r1<r2)std::swap(r1,r2);
db x1=sqr(R)/(2*r1);
db x2=sqr(R)/(2*r2);
db r=(x2-x1)/2;Pnt o((x1+x2)/2,0);
db nowr=get_r(o,r);
db ans=sqr(nowr);
int n;scanf("%d",&n);
for(int re i=2;i<=n;++i){
if((i&1)==0)o.y+=2*r,nowr=get_r(o,r);
ans+=sqr(nowr);if(sqr(nowr)*PI<eps)break;
}printf("%.5f\n",ans*PI);
}
}
void file(){
#ifdef zxyoi
freopen("designer.in","r",stdin);
#endif
}
signed main(){file();Main();return 0;}