bzoj 1502: [NOI2005]月下柠檬树

Description

Input

文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度)。第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度。第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的圆的半径。上述输入文件中的数据,同一行相邻的两个数之间用一个空格分隔。输入的所有实数的小数点后可能包含1至10位有效数字。

Output

输出1个实数,表示树影的面积。四舍五入保留两位小数。

Sample Input

2 0.7853981633
10.0 10.00 10.00
4.00 5.00

Sample Output

171.97

HINT

1≤n≤500,0.3


前段时间忙NOIP结果都没来写这题的题解。

simpson可以熟练应用了应该。。

投影=圆+切线的总面积。定点我们可以想象成一个r=0的圆。

然后切线的求法就是自己画个图。然后相似三角形一下就好了

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=1e-5;
struct circle
{
     double x,y;
     double r;
}a[10001];
struct circle2
{
     double x,y;
     double r;
     double ll,rr;
}sx[10001];
struct line
{
     double x1,y1,x2,y2;
}lin[10001];
double h[10001];
bool flag[10001];
int p,n;
inline double fabs(double x)
{
     if(x<0)
          x=-x;
     return x;
}
inline double max(double x,double y)
{
     if(x>y)
          return x;
     return y;
}
inline double geth(double x)
{
     int i;
     double len=0,dis;
     for(i=1;i<=n;i++)
     {
     	  if(sx[i].ll>=x||sx[i].rr<=x)
     	       continue;
          dis=sqrt(sx[i].r*sx[i].r-(sx[i].x-x)*(sx[i].x-x));
          len=max(len,dis*(double)2);
     }
     for(i=1;i<=p;i++)
     {
     	  if(lin[i].x1>x||lin[i].x2<x)
     	       continue;
          dis=(lin[i].y1+(lin[i].y2-lin[i].y1)/(lin[i].x2-lin[i].x1)*(x-lin[i].x1));
          len=max(len,dis*(double)2);
     }
     return len;
}
inline double cal(double len,double lh,double mh,double rh)
{
     return (lh+mh*(double)4+rh)*len/(double)6;
}
inline double simpson(double l,double mid,double r,double lh,double mh,double rh,double s)
{
     double mid1=(l+mid)/(double)2,mid2=(mid+r)/(double)2;
     double mh1=geth(mid1),mh2=geth(mid2);
     double s1=cal(mid-l,lh,mh1,mh),s2=cal(r-mid,mh,mh2,rh);
     if(fabs(s1+s2-s)<eps)
          return s1+s2;
     return simpson(l,mid1,mid,lh,mh1,mh,s1)+simpson(mid,mid2,r,mh,mh2,rh,s2);
}
int main()
{
     memset(flag,false,sizeof(flag));
     double alpha;
     scanf("%d%lf",&n,&alpha);
     int i,j;
     for(i=0;i<=n;i++)
     {
     	  scanf("%lf",&h[i]);
          if(i!=0)
               h[i]=h[i]+h[i-1];
          a[i+1].x=h[i]/tan(alpha);
          a[i+1].y=0;
     }
     double x;
     for(i=1;i<=n;i++)
     {
          scanf("%lf",&x);
          a[i].r=x;
     }
     for(i=1;i<=n;i++)
     {
     	  if(a[i+1].x-a[i].x<fabs(a[i+1].r-a[i].r))
     	       continue;
     	  p++;
          lin[p].x1=a[i].x-a[i].r*(a[i+1].r-a[i].r)/(a[i+1].x-a[i].x);
          lin[p].y1=a[i].y+sqrt(a[i].r*a[i].r-(a[i].x-lin[p].x1)*(a[i].x-lin[p].x1));
          lin[p].x2=a[i+1].x-a[i+1].r*(a[i+1].r-a[i].r)/(a[i+1].x-a[i].x);
          lin[p].y2=a[i+1].y+sqrt(a[i+1].r*a[i+1].r-(a[i+1].x-lin[p].x2)*(a[i+1].x-lin[p].x2));
     }
     for(i=1;i<=n;i++)
     {
          sx[i].r=a[i].r;
          sx[i].x=a[i].x;
          sx[i].y=a[i].y;
          sx[i].ll=a[i].x-a[i].r;
          sx[i].rr=a[i].x+a[i].r;
     }
     double l=sx[1].x-sx[1].r,r=lin[p].x2,mid,lh,rh,mh;
     for(i=1;i<=n;i++)
     {
          l=min(l,sx[i].ll);
          r=max(r,sx[i].rr);
     }
     mid=(l+r)/(double)2;
     double ans=0;
     lh=geth(l);
     rh=geth(r);
     mh=geth(mid);
     ans=simpson(l,mid,r,lh,mh,rh,cal(r-l,lh,mh,rh));
     printf("%.2lf\n",ans);
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值