【NOI2005】 月下柠檬树

题目描述
月下柠檬树
主文件名: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,表示柠檬树每层下底面的圆的半径。
上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。
输入的所有实数的小数点后可能包含 110 位有效数字。
【输出格式】
将你的结果输出到文件 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≤10010%的数据中,n=130%的数据中,n≤260%的数据中,n≤20100%的数据中,n≤500

 

 

题解

 

simpson自适应公式
 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 }

 

转载于:https://www.cnblogs.com/datam-cy/archive/2012/06/06/NOI2005-lemon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值