NC17399. [NOI2005]月下柠檬树
描述
李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 索着人生的哲理。
李哲是一个喜爱思考的孩子,当他看到在月光的照射下柠檬树投在地面上的
影子是如此的清晰,马上想到了一个问题:树影的面积是多大呢?
李哲知道,直接测量面积是很难的,他想用几何的方法算,因为他对这棵柠 檬树的形状了解得非常清楚,而且想好了简化的方法。
李哲将整棵柠檬树分成了 n 层,由下向上依次将层编号为 1,2,…,n。从第 1
到 n-1 层,每层都是一个圆台型,第 n 层(最上面一层)是圆锥型。对于圆台型, 其上下底面都是水平的圆。对于相邻的两个圆台,上层的下底面和下层的上底面 重合。第 n 层(最上面一层)圆锥的底面就是第 n-1 层圆台的上底面。所有的底面 的圆心(包括树顶)处在同一条与地面垂直的直线上。李哲知道每一层的高度为 h1,h2,…,hn,第 1 层圆台的下底面距地面的高度为 h0,以及每层的下底面的圆的 半径 r1,r2,…,rn。李哲用熟知的方法测出了月亮的光线与地面的夹角为 alpha。
为了便于计算,假设月亮的光线是平行光,且地面是水平的,在计算时忽略树干所产生的影子。李哲当然会算了,但是他希望你也来练练手。
输入描述
输入的第 1 行包含一个整数 n 和一个实数 alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。
第 2 行包含 n+1 个实数 h0,h1,h2,…,hn,表示树离地的高度和每层的高度。
第 3 行包含 n 个实数 r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。 上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。 输入的所有实数的小数点后可能包含 1 至 10 位有效数字。
输出描述
输出 1 个实数,表示树影的面积。四舍五入保留两位小数。
示例1
输入:
2 0.7853981633 10.0 10.00 10.00 4.00 5.00
输出:
171.97
C++14(g++5.4) 解法, 执行用时: 319ms, 内存消耗: 504K, 提交时间: 2019-08-20 21:48:17
#include<bits/stdc++.h> #define FOR(x,y,z) for(int x=y,x##_=z;x<=x##_;++x) #define DOR(x,y,z) for(int x=y,x##_=z;x>=x##_;--x) #define FOR_(x,y,z,s) for(int x=y,x##_=z;x<=x##_;x+=s) #define FOR__(x,y,z) for(int x=y,x##_=z;x<=x##_;x<<=1) #define EOR(x,y) for(int x##_=head[x],y=edge[x##_].e;x##_;y=edge[x##_=edge[x##_].to].e) #define EGOR(x,y,z) for(int x##_=head[x],y=edge[x##_].e,z=edge[x##_].c;x##_;y=edge[x##_=edge[x##_].to].e,z=edge[x##_].c) #define clr(x,y) memset(x,y,sizeof(x)) #define szf(x) sizeof(x) #define min3(x,y,z) min(min(x,y),z) #define max3(x,y,z) max(max(x,y),z) #define read2(x,y) read(x),read(y) #define read3(x,y,z) read(x),read(y),read(z) #define read4(x,y,z,w) read3(x,y,z),read(w) #define reads(str) sf("%s",str) #define ts (*this) #define sf scanf #define pf printf #define ll long long #define ull unsigned long long #define db long double #define ct clock_t #define ck() clock() #define rd rand() #define rmx RAND_MAX #define RD T*(rd*2-rmx) using namespace std; template<class T>bool tomin(T &x,T y){return x>y?x=y,1:0;} template<class T>bool tomax(T &x,T y){return x<y?x=y,1:0;} template<class T>void read(T &x){ char c; x=0; int f=1; while(c=getchar(),c<'0'||c>'9')if(c=='-')f=-1; do x=(x<<3)+(x<<1)+(c^48); while(c=getchar(),c>='0'&&c<='9'); x*=f; } const db Pi=acos(-1); const int maxn=505; int n; db al; struct node{ db x,r; }a[maxn]; namespace P10{ void solve(){ db r=a[1].r; if(a[1].x+a[1].r<a[2].x){ db d=acos(r/(a[2].x-a[1].x)); pf("%.2Lf",(Pi-d+tan(d))*r*r); }else pf("%.2Lf\n",Pi*r*r); } } namespace P100{ const db EPS=1e-6; const db EPPS=1e-15; #define pw(x) ((x)*(x)) bool ok[maxn]; db K[maxn],B[maxn]; db pl[maxn],pr[maxn]; bool cmp(db x,db y){ return y-x>=EPPS; } db F(db x){ db val=0; FOR(i,1,n)if(cmp(a[i].x-a[i].r,x)&&cmp(x,a[i].x+a[i].r)) tomax(val,sqrt(pw(a[i].r)-pw(a[i].x-x))); FOR(i,1,n-1)if(ok[i]&&cmp(pl[i],x)&&cmp(x,pr[i])) tomax(val,K[i]*x+B[i]); return val; } db Val(db a,db b){ return (b-a)/6*(F(a)+F(b)+F((a+b)/2)*4); } db solve(db a,db b,db V){ db mid=(a+b)/2; db Vl=Val(a,mid); db Vr=Val(mid,b); if(fabs(V-Vl-Vr)<EPS)return V; return solve(a,mid,Vl)+solve(mid,b,Vr); } db dis(db k,db b,db x){ return fabs(x*k+b)/sqrt(1+k*k); } void solve(){ FOR(i,1,n-1){ if(cmp(a[i+1].x+a[i+1].r,a[i].x+a[i].r))continue; if(cmp(a[i+1].x-a[i+1].r,a[i].x-a[i].r))continue; ok[i]=1; db th=asin((a[i+1].r-a[i].r)/(a[i+1].x-a[i].x)); K[i]=tan(th); B[i]=a[i].r*sqrt(K[i]*K[i]+1)-tan(th)*a[i].x; pl[i]=a[i].x-a[i].r*sin(th); pr[i]=a[i+1].x-a[i+1].r*sin(th); } db l=a[1].x-a[1].r; db r=a[n].x+a[n].r; FOR(i,1,n){ tomin(l,a[i].x-a[i].r); tomax(r,a[i].x+a[i].r); } pf("%.2Lf",solve(l,r,Val(l,r))*2); } } int main(){ srand(time(NULL)); read(n);n++; sf("%Lf",&al); al=(db)1/tan(al); db H=0; FOR(i,1,n){ sf("%Lf",&a[i].x); a[i].x=(H+=a[i].x)*al; } FOR(i,1,n-1)sf("%Lf",&a[i].r); if(n==2)P10::solve(); else P100::solve(); return 0; }
C++11(clang++ 3.9) 解法, 执行用时: 155ms, 内存消耗: 504K, 提交时间: 2019-03-16 15:33:22
#include <cmath> #include <cstdio> #include <algorithm> #define N 510 #define eps 1e-5 using namespace std; struct circle { double x , r; }c[N]; struct line { double x1 , y1 , x2 , y2; }l[N]; double h[N]; int n , m; inline double squ(double x) { return x * x; } inline double f(double p) { int i; double ans = 0; for(i = 1 ; i <= n ; i ++ ) if(p >= c[i].x - c[i].r && p <= c[i].x + c[i].r) ans = max(ans , sqrt(squ(c[i].r) - squ(p - c[i].x))); for(i = 1 ; i <= m ; i ++ ) if(p >= l[i].x1 && p <= l[i].x2) ans = max(ans , l[i].y1 + (p - l[i].x1) * (l[i].y2 - l[i].y1) / (l[i].x2 - l[i].x1)); return ans; } inline double calc(double l , double r) { return (r - l) * (f(l) + f(r) + f((l + r) / 2) * 4) / 6; } double simpson(double l , double r , double s) { double mid = (l + r) / 2 , x = calc(l , mid) , y = calc(mid , r); if(fabs(x + y - s) <= eps) return s; return simpson(l , mid , x) + simpson(mid , r , y); } int main() { int i; double alpha , t , L = 1e9 , R = -1e9; scanf("%d%lf" , &n , &alpha) , n ++ ; for(i = 1 ; i <= n ; i ++ ) scanf("%lf" , &h[i]) , h[i] += h[i - 1] , c[i].x = h[i] / tan(alpha); for(i = 1 ; i < n ; i ++ ) scanf("%lf" , &c[i].r); for(i = 1 ; i < n ; i ++ ) { if(c[i + 1].x - c[i].x > fabs(c[i + 1].r - c[i].r)) { m ++ ; t = c[i].r * (c[i].r - c[i + 1].r) / (c[i + 1].x - c[i].x) , l[m].x1 = c[i].x + t , l[m].y1 = sqrt(squ(c[i].r) - squ(t)); t = c[i + 1].r * (c[i].r - c[i + 1].r) / (c[i + 1].x - c[i].x) , l[m].x2 = c[i + 1].x + t , l[m].y2 = sqrt(squ(c[i + 1].r) - squ(t)); } } for(i = 1 ; i <= n + 1 ; i ++ ) L = min(L , c[i].x - c[i].r) , R = max(R , c[i].x + c[i].r); printf("%.2lf\n" , 2 * simpson(L , R , calc(L , R))); return 0; }