[NOI2005] 月下柠檬树

题意:

给定一棵由若干个圆台和圆锥组成的树,求这棵树在与地面成$\alpha$角的平行光束照射下产生的投影的面积。

$n\leq 500$。

 

题解:

显然投影下去之后每个圆的$r$不变,而高度$h$变成$\frac{h}{\tan{\alpha}}$。

圆的面积可以直接算,两个圆的公切线形成的梯形用三角函数推一下也可以直接算。

那么直接$Simpson$积分算一下就行了。注意区间$l,r$应该对所有圆算一遍$min,max$来取值,因为会出现圆套圆的情况。

复杂度$O(n^{2}\log{n})$(大概吧)。

 

套路:

  • 求一个整体复杂但可以求得单点极值的图形面积$\rightarrow$Simpson积分。

 

代码:

#include<bits/stdc++.h>
#define maxn 200005
#define maxm 500005
#define inf 0x7fffffff
#define eps 1e-6
#define ll long long
#define rint register int
#define debug(x) cerr<<#x<<": "<<x<<endl
#define fgx cerr<<"--------------"<<endl
#define dgx cerr<<"=============="<<endl

using namespace std;
int n; double H[maxn],R[maxn],C[maxn];

inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline double f(double x){
    double res=0; 
    for(rint i=1;i<=n;i++)
        if(C[i]-x<R[i] && C[i]-x>-R[i])
            res=max(res,sqrt(R[i]*R[i]-(C[i]-x)*(C[i]-x)));
    for(rint i=1;i<n;i++){
        double x1=C[i]+R[i]*(R[i]-R[i+1])/H[i];
        double x2=C[i+1]+R[i+1]*(R[i]-R[i+1])/H[i];
        if(x1<x && x2>x){
            double y1=sqrt(R[i]*R[i]-(C[i]-x1)*(C[i]-x1));
            double y2=sqrt(R[i+1]*R[i+1]-(C[i+1]-x2)*(C[i+1]-x2));
            res=max(res,y1+(x-x1)*(y2-y1)/(x2-x1));
        }
    }
    return res;
}

inline double simpson(double l,double r){return (r-l)*(f(l)+f(r)+4.0*f((l+r)/2.0))/6.0;}
inline double solve(double l,double r){
    double mid=(l+r)/2.0,S=simpson(l,r),S1=simpson(l,mid),S2=simpson(mid,r);
    return (abs(S1+S2-S)<eps)?(S1+S2):(solve(l,mid)+solve(mid,r));
}

int main(){
    n=read(); double theta; 
    scanf("%lf",&theta); 
    double tp=tan(theta);
    for(rint i=0;i<=n;i++) scanf("%lf",&H[i]),H[i]/=tp;
    for(rint i=1;i<=n;i++) scanf("%lf",&R[i]); 
    R[++n]=eps,C[1]=R[1]; 
    for(rint i=2;i<=n;i++) C[i]=C[i-1]+H[i-1];
    double l=0,r=0; 
    for(rint i=1;i<=n;i++) r=max(r,C[i]+R[i]),l=min(l,C[i]-R[i]);
    printf("%.2lf\n",solve(l,r)*2.0);
    return 0;
}
月下柠檬树

 

posted @ 2020-06-26 17:11  Fugtemypt  阅读(168)  评论(0编辑  收藏  举报