CQOI2010 传送带

题目链接:戳我

分别枚举线段AB上的出发点,和线段CD上的到达点,然后时间直接计算,取min就可以了。

但是这样子显然会T飞,(相当于1e5的平方吧?)所以我们进一步考虑性质。

然后打表(或者感性理解)可以发现分别选择点的时候,放进计算距离的式子里面其实是一个下凸的单峰函数(可以彼此独立打表,即随意固定一个出发点,打表达到点;或者随意固定一个达到点,打表出发点),然后我们就可以三分套三分了。(至于为什么可以分开打表看?主席说可以放到三维上面取理解,即在x坐标上是一个下凸的单峰函数,从y坐标看的时候压成了一个值,拓展出来三维的话还是下凸的(就像一个下陷的膜?))

感性理解的话就容易多了,画个图,把坐标从下往上移动的时候,靠下或者靠上的话都不优(因为或许会走冤枉路),所以就在中间取最优......好吧,我也解释不清楚了

不过。。。。还是不太清楚为什么直接上while会WA两个点QAQ

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
#define eps 1e-8
using namespace std;
double ax,ay,bx,by,cx,cy,dx,dy,p,q,r;
inline double dist(double x1,double y1,double x2,double y2)
    {return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
inline double calc(double x,double y)
{
    double lx=cx,ly=cy,rx=dx,ry=dy;
    double cur_ans=0.0;
    do
    {
        double xx1=(rx-lx)/3+lx,yy1=(ry-ly)/3+ly;
        double xx2=lx+rx-xx1,yy2=ly+ry-yy1;
        double k1=dist(x,y,ax,ay)/p+dist(x,y,xx1,yy1)/r+dist(xx1,yy1,dx,dy)/q;
        double k2=dist(x,y,ax,ay)/p+dist(x,y,xx2,yy2)/r+dist(xx2,yy2,dx,dy)/q;
        if(k1>k2) cur_ans=k1,lx=xx1,ly=yy1;
        else cur_ans=k2,rx=xx2,ry=yy2;
    }while(fabs(rx-lx)>eps||fabs(ry-ly)>eps);
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&ax,&ay,&bx,&by,&cx,&cy,&dx,&dy);
    scanf("%lf%lf%lf",&p,&q,&r);
    double ans=0.0,lx=ax,ly=ay,rx=bx,ry=by;
    do
    {
        double xx1=(rx-lx)/3+lx,yy1=(ry-ly)/3+ly;
        double xx2=lx+rx-xx1,yy2=ly+ry-yy1;
        double k1=calc(xx1,yy1),k2=calc(xx2,yy2);
        if(k1>k2) lx=xx1,ly=yy1,ans=k1;
        else rx=xx2,ry=yy2,ans=k2;
    }while(fabs(rx-lx)>eps||fabs(ry-ly)>eps);
    printf("%.2lf
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/fengxunling/p/10803049.html