P4207题解
蒟蒻硬肝了两天才肝懂这道题,我太难了~~~
题目大意
求几个在竖直方向连续的圆台和圆锥在仰角为
分析
1.
由于这个影子可能很奇怪(复杂),所以考虑积分,即
2.
首先求出投影下来要变化的量,思考一下,可以发现只有
导一下角,用三角函数即可求出投影下来的长度。
3.
考虑一下圆台的阴影怎么求。因为圆台的两个圆与地面平行(都为水平),所以它们会在地上投影出两个一模一样的圆,圆心的间距
因为我们要求积分,所以得先求解析式,才能套板板,于是得用初中知识--相似
核心推导都在图里,其它的边可以用比例和勾股定理求出,求得
4.
若两个大圆中间夹着一个小圆,它们的公切线就会相交,需要在求积分的时候注意一下,取最大值。
若两个小圆中间夹着一个大圆,它们的公切线中间就会出现一段圆弧,需要在求积分的时候用勾股定理计算。
若一个大圆包着一个小圆,也是求最大值。
注意最顶上的圆锥可以视为一个圆面的半径为
Code
#include <bits/stdc++.h>
#define jd 1e-7
#define D double
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
#define fr(x,y,p) for(int x=y;p;++x)
#define rf(x,y,p) for(int x=y;p;--x)
#define abs(x)(x>0?x:-(x))//这里的-(x)要打括号!!!
using namespace std;
struct cir{
D x,r;
}a[505];
struct cut_line{//cir[i]->cir[i+1]切线
D k,b,l,r;
}p[505];
int n;
D alpha;
void calc_cut_line(int x,int y){
if(abs(a[x].r-a[y].r)<=jd){
p[x].k=0,p[x].b=a[x].r,p[x].l=a[y].x,p[x].r=a[y].x;
return;
}
if(a[x].r>a[y].r){
D ac=a[y].x-a[x].x,aj=a[x].r-a[y].r,S_ckh=aj/ac,ch=a[x].r*S_ckh,ag=a[y].r*S_ckh,kh=sqrt(a[x].r*a[x].r-ch*ch),lg=sqrt(a[y].r*a[y].r-ag*ag);//推导过程
p[x].k=(lg-kh)/(ac-ch+ag),p[x].b=lg-(a[y].x+ag)*p[x].k,p[x].l=a[x].x+ch,p[x].r=a[y].x+ag;
}else{
D ac=a[y].x-a[x].x,aj=a[y].r-a[x].r,S_ckh=aj/ac,ch=a[y].r*S_ckh,ag=a[x].r*S_ckh,kh=sqrt(a[y].r*a[y].r-ch*ch),lg=sqrt(a[x].r*a[x].r-ag*ag);//推导过程
p[x].k=(kh-lg)/(ac-ch+ag),p[x].b=lg-(a[x].x-ag)*p[x].k,p[x].l=a[x].x-ag,p[x].r=a[y].x-ch;
}
}
D f(D x){
D ans=0;//求已知的对应点y的最大值
fr(i,1,i<=n){//与圆的交点
if(x>a[i].x-a[i].r&&x<a[i].x+a[i].r)//取不取等看心情
ans=max(ans,sqrt(a[i].r*a[i].r-(a[i].x-x)*(a[i].x-x)));
}
fr(i,1,i<n){
if(x>=p[i].l&&x<=p[i].r)
ans=max(ans,p[i].k*x+p[i].b);
}
return ans;
}
D Simpson(D l,D r){
return (r-l)*(f(r)+f(l)+f((r+l)/2)*4)/6;
}
D jf(D l,D r,D sum){
D mid=(l+r)/2,le=Simpson(l,mid),ri=Simpson(mid,r);
if(abs(le+ri-sum)<=jd) return le+ri;
else return jf(l,mid,le)+jf(mid,r,ri);
}
int main() {
scanf("%d %lf",&n,&alpha);
alpha=1/tan(alpha),a[++n].r=0;
fr(i,1,i<=n){
scanf("%lf",&a[i].x);
a[i].x*=alpha;
if(i>0) a[i].x+=a[i-1].x;
}
fr(i,1,i<n) scanf("%lf",&a[i].r);
fr(i,1,i<n) calc_cut_line(i,i+1);
D l,r;
fr(i,1,i<=n) l=min(l,a[i].x-a[i].r),r=max(r,a[i].x+a[i].r);
printf("%.2lf",2*jf(l,r,Simpson(l,r)));
return 0;
}