1. 程式人生 > >[日常摸魚]bzoj1502[NOI2005]月下檸檬樹-簡單幾何+Simpson法

[日常摸魚]bzoj1502[NOI2005]月下檸檬樹-簡單幾何+Simpson法

targe int 參考 2.0 math ont bzoj close blank

關於自適應Simpson法的介紹可以去看我的另一篇blog

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

題意:空間裏圓心在同一直線上且底面與地面平行的若幹個圓臺和頂層的圓錐以$\alpha$的角度投影到地面,求投影的面積。


(其實我是看po姐博客來的x)

首先把圓錐的頂點也看成一個半徑為0的圓滿,對於每個高度為$h$的圓投影下去的坐標是$h/tan(\alpha)$,半徑不變,而對於圓臺的側面投影下去是上下底兩個圓的切線。

技術分享圖片

關於兩個圓的切線可以像圖上這樣求(參考po姐博客的x)

$\sin(\alpha)=\frac{r_{i-1}-r_i}{x_i-x_{i-1}}$

這個式子同樣可以適用於其他情況,然後三角函數搞一下求出其他點的坐標,根據坐標的範圍用Simpson法來求面積。

只是把求點的函數值改成掃一遍所有的點和圓,找最大值。

哦然後我的Simpson遞歸的時候本來是讓eps乘上$\frac{1}{2}$的…但是這樣會T掉,不乘又會wa…orz

然後改成$\frac{2}{3}$就可以了…跑900+ms真神奇

技術分享圖片
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const
int N=515; struct point { double x,y; }; struct line { point p1,p2; double k,b; line(){} void modify(double x1,double y1,double x2,double y2) { p1.x=x1;p1.y=y1; p2.x=x2;p2.y=y2; k=(p1.y-p2.y)/(p1.x-p2.x); b=p1.y-k*p1.x; } double f(double
x) { return k*x+b; } }ls[N]; struct circle { double x,r; }cs[N]; int n,tot;double alpha; inline double f(double x) { double res=0;double eps=1e-6; for(register int i=1;i<=n;i++) { double dis=fabs(x-cs[i].x); if(dis-cs[i].r>-eps)continue; double y=sqrt(cs[i].r*cs[i].r-dis*dis); res=max(res,y); } for(register int i=1;i<=tot;i++) { if(!(ls[i].p1.x<=x&&x<=ls[i].p2.x))continue; double y=ls[i].f(x); res=max(res,y); } return res; } inline double calc(double l,double r) { double mid=l+(r-l)/2; return (f(l)+4.0*f(mid)+f(r))*(r-l)/6.0; } inline double asr(double l,double r,double area,double eps) { double mid=l+(r-l)/2; double L=calc(l,mid),R=calc(mid,r); if(fabs(L+R-area)<=eps*10.0)return L+R+(L+R-area)/10.0; return asr(l,mid,L,eps*2.0/3.0)+asr(mid,r,R,eps*2.0/3.0); } inline double solve(double l,double r,double eps) { return asr(l,r,calc(l,r),eps); } int main() { //freopen("input.in","r",stdin); double eps=1e-6,l,r;l=r=0; scanf("%d%lf",&n,&alpha);alpha=1/(tan(alpha)); for(register int i=1;i<=n+1;i++) { scanf("%lf",&cs[i].x); cs[i].x*=alpha; cs[i].x+=cs[i-1].x; } for(register int i=1;i<=n;i++) { scanf("%lf",&cs[i].r); } for(register int i=1;i<=n+1;i++) { l=min(l,cs[i].x-cs[i].r); r=max(r,cs[i].x+cs[i].r); } for(register int i=2;i<=n+1;i++) { double L=cs[i].x-cs[i-1].x; if(L-fabs(cs[i].r-cs[i-1].r)<eps)continue; //double sin_alpha=fabs(cs[i].r-cs[i-1].r)/L; double sin_alpha=(cs[i-1].r-cs[i].r)/L; double cos_alpha=sqrt(1-sin_alpha*sin_alpha); ls[++tot].modify(cs[i-1].x+cs[i-1].r*sin_alpha,cs[i-1].r*cos_alpha, cs[i].x+cs[i].r*sin_alpha,cs[i].r*cos_alpha); } printf("%.2lf",solve(l,r,eps)*2.0); return 0; }
View Code

[日常摸魚]bzoj1502[NOI2005]月下檸檬樹-簡單幾何+Simpson法