

月下柠檬树 主文件名:lemon 【问题描述】 李哲非常非常喜欢柠檬树, 特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时, 他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 索着人生的哲理。 李哲是一个喜爱思考的孩子, 当他看到在月光的照射下柠檬树投在地面上的 影子是如此的清晰,马上想到了一个问题:树影的面积是多大呢? 李哲知道,直接测量面积是很难的,他想用几何的方法算,因为他对这棵柠 檬树的形状了解得非常清楚,而且想好了简化的方法。 李哲将整棵柠檬树分成了 n 层,由下向上依次将层编号为 1,2,...,n。从第 1 到 n-1 层,每层都是一个圆台型,第 n 层(最上面一层)是圆锥型。对于圆台型, 其上下底面都是水平的圆。 对于相邻的两个圆台,上层的下底面和下层的上底面 重合。第 n 层(最上面一层)圆锥的底面就是第 n-1 层圆台的上底面。所有的底面 的圆心(包括树顶)处在同一条与地面垂直的直线上。李哲知道每一层的高度为 h1,h2,...,hn,第 1 层圆台的下底面距地面的高度为 h0,以及每层的下底面的圆的 半径 r1,r2,...,rn。李哲用熟知的方法测出了月亮的光线与地面的夹角为 alpha。 柠檬树的纵剖面图 图 2 月光角度示意图 为了便于计算,假设月亮的光线是平行光,且地面是水平的,在计算时忽略 树干所产生的影子。李哲当然会算了,但是他希望你也来练练手。 【输入格式】 从文件 lemon.in 中读入数据。 文件的第 1 行包含一个整数 n 和一个实数 alpha,表示柠檬树的层数和月亮 的光线与地面夹角(单位为弧度)。 第 2 行包含 n+1 个实数 h0,h1,h2,...,hn,表示树离地的高度和每层的高度。 第 3 行包含 n 个实数 r1,r2,...,rn,表示柠檬树每层下底面的圆的半径。 上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。 输入的所有实数的小数点后可能包含 1 至 10 位有效数字。 【输出格式】 将你的结果输出到文件 lemon.out 中。 输出 1 个实数,表示树影的面积。四舍五入保留两位小数。 【输入样例】 2 0.7853981633 10.0 10.00 10.00 4.00 5.00 【输出样例】 171.97 【数据范围】 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。


1 /* 2 *Problem: NOI2005 月下柠檬树 3 *Author : Chen Yang 4 *State : Solved 5 *time : 2012.6.6 4:25 pm 6 *Memo : simpson自适应公式 7 */ 8 #include <cstdio> 9 #include <cstdlib> 10 #include <cmath> 11 #define sqr(x) ((x)*(x)) 12 #define max(a, b) ((a) > (b) ? (a) : (b)) 13 typedef double DB; 14 const int maxn=510; const DB zero=1e-6; 15 int n; DB alp, h, x[maxn], R[maxn], fx1[maxn], fx2[maxn], fy1[maxn], fy2[maxn]; 16 DB f(DB X) 17 { 18 DB s = 0; 19 for (int i=1; i<=n; ++i) 20 { 21 if (fabs(x[i]-X)<R[i]) s = max(s, sqrt(sqr(R[i])-sqr(x[i]-X))); 22 if (x[i+1]-x[i]>fabs(R[i+1]-R[i]) && fx1[i]<X && X<fx2[i]) 23 s = max(s, (fy2[i]-fy1[i])/(fx2[i]-fx1[i])*(X-fx1[i])+fy1[i]); 24 } 25 return s; 26 } 27 DB simpson(DB a, DB b, DB fa, DB fb, DB fm) { return (b-a)/6*(fa+4*fm+fb); } 28 DB area(DB l, DB fl, DB m, DB fm, DB r, DB fr, DB pre) 29 { 30 DB ls=(l+m)/2, rs=(m+r)/2, fls=f(ls), frs=f(rs); 31 DB la=simpson(l,m,fl,fm,fls), ra=simpson(m,r,fm,fr,frs); 32 return fabs(la+ra-pre)<zero? pre:area(l,fl,ls,fls,m,fm,la)+area(m,fm,rs,frs,r,fr,ra); 33 } 34 int main() 35 { 36 freopen("lemon.in", "r", stdin); 37 freopen("lemon.out", "w", stdout); 38 scanf("%d%lf", &n, &alp); alp = 1/tan(alp); 39 for (int i=1; i<n+2; ++i) scanf("%lf", &x[i]), h += x[i], x[i] = h*alp; 40 DB l = x[n+1], r = l; 41 for (int i=1; i<n+1; ++i) 42 scanf("%lf", &R[i]), l = l<x[i]-R[i]? l:x[i]-R[i], r = r>x[i]+R[i]? r:x[i]+R[i]; 43 for (int i=1; i<n+1; ++i) 44 fx1[i] = x[i]+R[i]*(R[i]-R[i+1])/(x[i+1]-x[i]), fy1[i] = sqrt(sqr(R[i])-sqr(fx1[i]-x[i])), 45 fx2[i] = x[i+1]+R[i+1]*(R[i]-R[i+1])/(x[i+1]-x[i]), fy2[i] = sqrt(sqr(R[i+1])-sqr(fx2[i]-x[i+1])); 46 DB m = (l+r)/2, fm = f(m), fl = f(l), fr = f(r); 47 printf("%.2lf", 2*area(l,fl,m,fm,r,fr,simpson(l,r,fl,fr,fm))); 48 return 0; 49 }