hdu 4816,Bathysphere,三分

1 篇文章 0 订阅
今天模拟了去年长春Regional。
我们队居然做到了五题,20名左右的样子。
可惜最后一个小时开两道题都没做出来。

这题是其中之一:
给你n个点,相邻点连线,求一段长d区间的高度期望最大值。


算法如下:
高度是就是面积除以区间长度。
这样就是求面积的最大值。
面积的二阶导数是斜率,定值。因此可用三分法求极值。
枚举所有给定的点作为左端点或右端点,在到下一个端点之间一段区间内做三分求最大值即可。

听说现场赛卡三分。。求导可以直接求出极值。哎数学弱就要被吊打……

三分代码,G++可以过,C++会T哟。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define Maxn 200100
#define eps 1e-8

inline double getarea(double hk,double hy,double tk,double ty,double len){
    return (ty+ty+len*tk)*len/2.0-(hy+hy+len*hk)*len/2.0;
}

void work(double nowarea,double hk,double hy,double tk,double ty,double tlen,double &ans){
    double l=0,r=tlen,ll,rr,tmp,al,ar;
    while(r-l>eps){
        ll=(l+l+r)/3.0;
        rr=(l+r+r)/3.0;
        al=getarea(hk,hy,tk,ty,ll);
        ar=getarea(hk,hy,tk,ty,rr);
        if (al<ar) l=ll;
        else r=rr;
    }
    tmp=getarea(hk,hy,tk,ty,l);
    if (nowarea+tmp>ans) ans=nowarea+tmp;
}

int x[Maxn],y[Maxn];
double area[Maxn];

int main(){
    //freopen("din.txt","r",stdin);
    int cas,n,l,may,d,i;
    int nh,nt;
    double headx,heady,tailx,taily,kh,kt,tmpl,nowarea,ans;
    double len1,len2;
    scanf("%d",&cas);
    while(cas--){
        scanf("%d%d",&n,&l);
        may=0;
        for(i=1;i<=n;++i){
            scanf("%d%d",&x[i],&y[i]);
            if (y[i]>may) may=y[i];
        }
        x[n+1]=l+1;
        y[n+1]=y[n]+1;
        scanf("%d",&d);
        if (d==0) {printf("%.3lf\n",may);continue;}
        d=2*d;
        area[0]=area[1]=0;
        for(i=2;i<=n;++i){
            area[i]=area[i-1]+((double)y[i-1]+y[i])*((double)x[i]-x[i-1])/2.0;
        }
        for(i=1;i<=n;++i){
            if (d>=x[i]&&d<x[i+1]) {break;}
        }
        nh=2;nt=i+1;
        kh=((double)y[2]-y[1])/((double)x[2]-x[1]);
        kt=((double)y[nt]-y[nt-1])/((double)x[nt]-x[nt-1]);
        headx=x[1],heady=y[1];
        tailx=d;taily=y[nt-1]+kt*(d-x[nt-1]);
        nowarea=ans=area[nt-1]+(d-x[nt-1])/2.0*(y[nt-1]+y[nt-1]+kt*(d-x[nt-1]));
        while(1){
            if (tailx+eps>=l) break;
            len1=x[nh]-headx;
            len2=x[nt]-tailx;
            if (len1<len2) tmpl=len1;
            else tmpl=len2;
            work(nowarea,kh,heady,kt,taily,tmpl,ans);
            nowarea=nowarea+getarea(kh,heady,kt,taily,tmpl);
            if (len1<len2){
                headx=x[nh];
                heady=y[nh];
                tailx+=tmpl;
                taily+=kt*tmpl;
                nh+=1;
                kh=((double)y[nh]-y[nh-1])/((double)x[nh]-x[nh-1]);

            }
            else{
                headx+=tmpl;
                heady+=kh*tmpl;
                tailx=x[nt];
                taily=y[nt];
                nt+=1;
                kt=((double)y[nt]-y[nt-1])/((double)x[nt]-x[nt-1]);
            }
        }
        printf("%.3lf\n",ans/(1.0*d));
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值