1502: [NOI2005]月下柠檬树
Time Limit: 5 Sec
Memory Limit: 64 MB
Submit: 250
Solved: 148
[ Submit][ Status][ Discuss]
Description
李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思索着人生的哲理。
李哲是一个喜爱思考的孩子,当他看到在月光的照射下柠檬树投在地面上的影子是如此的清晰,马上想到了一个问题:树影的面积是多大呢?
李哲知道,直接测量面积是很难的,他想用几何的方法算,因为他对这棵柠檬树的形状了解得非常清楚,而且想好了简化的方法。
李哲将整棵柠檬树分成了 n 层,由下向上依次将层编号为 1,2,...,n。从第 1到 n-1 层,每层都是一个圆台型,第 n 层(最上面一层)是圆锥型。对于圆台型,其上下底面都是水平的圆。对于相邻的两个圆台,上层的下底面和下层的上底面重合。第 n 层(最上面一层)圆锥的底面就是第 n-1 层圆台的上底面。所有的底面的圆心(包括树顶)处在同一条与地面垂直的直线上。李哲知道每一层的高度为h1,h2,...,hn,第 1 层圆台的下底面距地面的高度为 h0,以及每层的下底面的圆的半径 r1,r2,...,rn。李哲用熟知的方法测出了月亮的光线与地面的夹角为 alpha。
Input
文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。 第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度。 第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。 上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。 输入的所有实数的小数点后可能包含1至10位有效数字。
Output
输出1个实数,表示树影的面积。四舍五入保留两位小数。
Sample Input
2 0.7853981633
10.0 10.00 10.00
4.00 5.00
Sample Output
171.97
HINT
1≤n≤500,0.3<alpha<π 2,0<hi≤100,0<ri≤100。
10%的数据中,n=1。
30%的数据中,n≤2。
60%的数据中,n≤20。
100%的数据中,n≤500。
这题是Simpson模版题。
有一个关键是圆的公切线的求法。
首先延长圆的切线求l,再求θ,最后用相似三角形。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (500+10)
#define eps 1e-8
double h[MAXN],s[MAXN],r[MAXN],alpha,l1=0,r1=0;
double sqr(double x){return x*x;}
int n,size=0;
struct S
{
double x,y,p,q;
}c[MAXN];
double f(double l)
{
double t=0.0;
for (int i=0;i<n;i++)
{
if (fabs(s[i]-l)<r[i]) t=max(t,sqrt(sqr(r[i])-sqr(s[i]-l)));
}
for (int i=1;i<=size;i++)
{
if (c[i].x<l&&l<c[i].p) t=max(t,c[i].y+(c[i].q-c[i].y)*(l-c[i].x)/(c[i].p-c[i].x));
}
return t;
}
double simpson(double l,double r,double fl,double fmid,double fr)
{
return (fl+4*fmid+fr)*(r-l)/6;
}
double rsimpson(double l,double r,double fl,double fmid,double fr)
{
double m=(l+r)/2;
double p=f((l+m)/2),q=f((m+r)/2);
double x=simpson(l,r,fl,fmid,fr),y=simpson(l,m,fl,p,fmid),z=simpson(m,r,fmid,q,fr);
if (fabs(x-y-z)<eps)
return y+z;
return rsimpson(l,m,fl,p,fmid)+rsimpson(m,r,fmid,q,fr);
}
int main()
{
scanf("%d%lf",&n,&alpha);
alpha=1/tan(alpha);
for (int i=0;i<=n;i++)
{
scanf("%lf",&h[i]);
if (i) h[i]+=h[i-1];
s[i]=h[i]*alpha;
}
for (int i=0;i<n;i++)
{
scanf("%lf",&r[i]);
l1=min(l1,s[i]-r[i]);
r1=max(r1,s[i]+r[i]);
}
r[n]=0;
for (int i=0;i<n;i++)
{
double d=s[i+1]-s[i];
if (d>fabs(r[i]-r[i+1]))
{
c[++size].x=s[i]-r[i]*(r[i+1]-r[i])/d;
c[size].y=sqrt(sqr(r[i])-sqr(c[size].x-s[i]));
c[size].p=s[i+1]-r[i+1]*(r[i+1]-r[i])/d;
c[size].q=sqrt(sqr(r[i+1])-sqr(c[size].p-s[i+1]));
}
}
r1=max(r1,s[n]);
printf("%.2lf",2*rsimpson(l1,r1,0,f((l1+r1)/2),0));
return 0;
}