码迷,mamicode.com
首页 > 其他好文 > 详细

[日常摸鱼]bzoj1502[NOI2005]月下柠檬树-简单几何+Simpson法

时间:2018-01-03 22:32:10      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:continue   htm   cstring   src   ons   递归   sqrt   坐标   abs   

关于自适应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法

标签:continue   htm   cstring   src   ons   递归   sqrt   坐标   abs   

原文地址:https://www.cnblogs.com/yoooshinow/p/8185614.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!