1. 程式人生 > >BZOJ1502:[NOI2005]月下檸檬樹——題解

BZOJ1502:[NOI2005]月下檸檬樹——題解

problem blog 兩個 圓心 幾何 png -a 參考 shadow

https://www.lydsy.com/JudgeOnline/problem.php?id=1502

https://www.luogu.org/problemnew/show/P4207

李哲非常非常喜歡檸檬樹,特別是在靜靜的夜晚,當天空中有一彎明月溫柔地照亮地面上的景物時,他必會悠閑地坐在他親手植下的那棵檸檬樹旁,獨自思索著人生的哲理。李哲是一個喜愛思考的孩子,當他看到在月光的照射下檸檬樹投在地面上的影子是如此的清晰,馬上想到了一個問題:樹影的面積是多大呢?李哲知道,直接測量面積是很難的,他想用幾何的方法算,因為他對這棵檸檬樹的形狀了解得非常清楚,而且想好了簡化的方法。李哲將整棵檸檬樹分成了n 層,由下向上依次將層編號為1,2,…,n。從第1到n-1 層,每層都是一個圓臺型,第n 層(最上面一層)是圓錐型。對於圓臺型,其上下底面都是水平的圓。對於相鄰的兩個圓臺,上層的下底面和下層的上底面重合。第n 層(最上面一層)圓錐的底面就是第n-1 層圓臺的上底面。所有的底面的圓心(包括樹頂)處在同一條與地面垂直的直線上。李哲知道每一層的高度為h1,h2,…,hn,第1 層圓臺的下底面距地面的高度為h0,以及每層的下底面的圓的半徑r1,r2,…,rn。李哲用熟知的方法測出了月亮的光線與地面的夾角為alpha。
技術分享圖片 為了便於計算,假設月亮的光線是平行光,且地面是水平的,在計算時忽略樹幹所產生的影子。 李哲當然會算了,但是他希望你也來練練手。

參考:https://www.luogu.org/blog/ACdreamer/solution-p4207

超級細節之計算幾何題。

面積的並選擇用自適應辛普森求,我們只取x軸以上的部分,最後答案*2即可。

於是我們需要做到給定x求y,就需要求出這一坨投射的陰影的每個部分的函數(圓的部分可以用幾何求y)。

於是需要求出圓的公切線的解析式。

首先對於高度h,投射後的長度為cota*h,圓的大小沒有改變。

然後就是貼心的兩張圖了,根據這兩張圖,再結合你的初中幾何知識,相信你一定能推出來的!

技術分享圖片

技術分享圖片

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef double dl;
const int N=510;
const dl eps=1e-8;
struct cir{
    dl x,r;
}p[N];
struct line{
    dl k,b,l,r;
}q[N];
int n; dl alpha; inline dl py(dl a,dl b){return sqrt(a*a-b*b);} inline dl f(dl x){ dl ans=0; for(int i=1;i<=n;i++){ if(p[i].x-p[i].r<x&&x<p[i].x+p[i].r){ ans=max(ans,py(p[i].r,x-p[i].x)); } } for(int i=1;i<n;i++){ if(q[i].l<=x&&x<=q[i].r){ ans=max(ans,q[i].k*x+q[i].b); } } return ans; } inline dl simpson(dl l,dl r){ dl mid=(l+r)/2; return (f(l)+4*f(mid)+f(r))*(r-l)/6; } inline dl asr(dl l,dl r,dl ans){ dl mid=(l+r)/2; dl l1=simpson(l,mid),r1=simpson(mid,r); if(fabs(l1+r1-ans)<eps)return l1+r1; return asr(l,mid,l1)+asr(mid,r,r1); } inline int shadow(dl a){ dl c=a*alpha; dl d=sqrt(a*a+c*c); return c*a/d; } inline void getl(int x,int y){ if(fabs(p[x].r-p[y].r)<eps){ q[x].l=p[x].x,q[x].r=p[y].x; q[x].k=0;q[x].b=p[x].r; return; } dl CA=p[y].x-p[x].x,AJ=fabs(p[x].r-p[y].r); dl CG=p[x].r,AB=p[y].r; dl CK=CG*AJ/CA,AI=AB*AJ/CA; if(p[x].r>p[y].r){ q[x].l=p[x].x+CK;q[x].r=p[y].x+AI; dl x1=q[x].l,y1=py(CG,CK); dl x2=q[x].r,y2=py(AB,AI); q[x].k=(y1-y2)/(x1-x2); q[x].b=y1-q[x].k*x1; }else{ q[x].l=p[x].x-CK;q[x].r=p[y].x-AI; dl x1=q[x].l,y1=py(CG,CK); dl x2=q[x].r,y2=py(AB,AI); q[x].k=(y1-y2)/(x1-x2); q[x].b=y1-q[x].k*x1; } } int main(){ scanf("%d%lf",&n,&alpha); alpha=1.0/tan(alpha); for(int i=1;i<=n+1;i++){ scanf("%lf",&p[i].x); p[i].x*=alpha; p[i].x+=p[i-1].x; } for(int i=1;i<=n;i++)scanf("%lf",&p[i].r); p[++n].r=0; for(int i=1;i<n;i++){ getl(i,i+1); } dl l=p[1].x-p[1].r,r=p[n].x; for(int i=1;i<=n;i++){ r=max(r,(p[i].x+p[i].r)); l=min(l,(p[i].x-p[i].r)); } printf("%.2lf\n",2*asr(l,r,simpson(l,r))); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ1502:[NOI2005]月下檸檬樹——題解