1 条题解

  • 0
    @ 2025-8-24 21:47:23

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 辰星凌
    时过而不知泪已落 —散华礼弥

    搬运于2025-08-24 21:47:23,当前版本为作者最后更新于2020-04-22 21:18:51,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    【题解】妖怪 [SCOI2016] [P3291] [Bzoj4570]

    My Blog\mathcal{My}\ \mathcal{Blog}

    传送门:妖怪 [SCOI2016] P3291]\text{[SCOI2016] P3291]} [Bzoj4570]\text{[Bzoj4570]}

    【题目描述】

    给出 nn (n106)(n\leqslant 10^6) 个点 (xi,yi)(x_i,y_i),设 fi(a,b)=xi+yi+bxia+ayibf_i(a,b)=x_i+y_i+\frac{bx_i}{a}+\frac{ay_i}{b},求出一组 (a,b)(a,b),使得 max{fi[1,n](a,b)}\max\{f_{i\in[1,n]}(a,b)\} 最小,输出这个最小值。

    【分析】

    感觉网上很多题解都没讲清楚。

    【Solution #1】

    k=bak=\frac{b}{a},则上面的函数可以转换为 fi(k)=xi+yi+kxi+yikf_i(k)=x_i+y_i+kx_i+\frac{y_i}{k}

    求最大的最小很明显要二分,每次检查是否存在一个正实数 kk 满足所有点的 f(k)f(k) 都小于等于 midmid 。即判断这个不等式组是否有解:

    $\begin{cases}f_1(k)\leqslant mid\\f_2(k)\leqslant mid\\...\\f_n(k)\leqslant mid \end{cases}$

    易知 fif_i 是一个双勾函数, 我们可以通过解关于 kk 的一元二次方程 fi(k)=midf_i(k)=mid 得出 kk 的一(两)个解 r1,r2r_1,r_2 (r1r2)(r_1\leqslant r_2),则当 k[r1,r2]k\in[r_1,r_2] 时一定满足 fi(k)midf_i(k)\leqslant mid 。对所有点求出 kk 的合法区间,最后判断是否存在交集即可。

    时间复杂度:O(nloginf)O(n\log \inf),可能会 TLETLE,但卡一卡貌似能水过。

    代码就不放了()。

    【Solution #2】

    此为正解。

    k=bak=-\frac{b}{a},则 fi(k)=xi+yikxiyikf_i(k)=x_i+y_i-kx_i-\frac{y_i}{k}(依然是双勾函数)。

    假设有一条斜率为 kk 且经过了点 (xi,yi)(x_i,y_i) 的直线,则该直线点斜式可表示为 y=kx+(yikxi)y=kx+(y_i-kx_i),其横纵截距分别为 kxiyik\frac{kx_i-y_i}{k}yikxiy_i-kx_i

    把这玩意儿加起来试试?

    $(\frac{kx_i-y_i}{k})+(y_i-kx_i)=x_i+y_i-kx _i-\frac{y_i}{k}$

    发现其表示式和 fi(k)f_i(k) 一模一样!。

    也就是说 fi(k)f_i(k) 的实质是斜率为 kk 且过点 (xi,yi)(x_i,y_i) 的直线横纵截距之和。

    假设当前 kk 已经确定,则计算 max{fi[1,n](k)}\max\{f_{i\in[1,n]}(k)\} 的过程就是个线性规划,易知该直线与上凸包的切点处 f(k)f(k) 值最大。

    反过来想,对于凸包上的每一个点 ii,考虑在什么情况下 fi(k)f_i(k) 大于等于其他所以点的 f(k)f(k),然后在合法情况中找到最小的 fif_i 来更新答案。设点 ii 在凸包上左右相邻两点与 ii 所形成的直线斜率分别为 k1,k2k_1,k_2 (k1>k2)(k_1 > k_2),则仅当 kk(,k2][k1,)(-\infty,k_2]\cup [k_1,\infty) 中取值时合法(只有此时才能满足直线与凸包切点恰好为 ii

    已知当 k=yixi-k=\frac{y_i}{x_i}fif_i 可取得最小值(均值不等式),如果 k=yixik=-\frac{y_i}{x_i} 在上述合法值域内,那么 fi(yixi)f_i(-\frac{y_i}{x_i}) 就可以作为一个答案的候选项。

    如果 k=yixik=-\frac{y_i}{x_i} 不在上述合法区域内,那么就要想办法找到其他 kk 使得 fi(k)f_i(k) 尽量小,由于双勾函数的性质, kk 越接近 yixi-\frac{y_i}{x_i} 函数值就越小,所以直接取 k=krk=krk=klk=kl 的情况进行决策即可。

    除了求上凸包要排序,决策都是线性的,时间复杂度:O(nlogn)O(n\log n)

    (毒瘤 OIOI 的算几依旧是这么毒瘤,不过这次代码长度倒是挺良心的)

    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LD double
    #define LL long long
    #define Vector Point
    #define Re register int
    using namespace std;
    const int N=1e6+3;
    const LD eps=1e-8;
    inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
    int n,t;LD ans=1e18;
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    struct Point{int x,y;Point(Re X=0,Re Y=0){x=X,y=Y;}}P[N],cp[N];
    inline LL Cro(Vector a,Vector b){return (LL)a.x*b.y-(LL)a.y*b.x;}
    inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    inline bool cmp(const Point &A,const Point &B){return A.x!=B.x?A.x<B.x:A.y>B.y;}
    inline LD getk(Point a,Point b){return (LD)(a.y-b.y)/(a.x-b.x);}
    inline LD calc(Point a,LD k){return dcmp(k)?a.x+a.y-a.x*k-a.y/k:1e18;}
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n);
        for(Re i=1;i<=n;++i)in(P[i].x),in(P[i].y);
        sort(P+1,P+n+1,cmp);
        for(Re i=1;i<=n;++i){
            while(t>1&&Cro(cp[t]-cp[t-1],P[i]-cp[t-1])>=0)--t;
            cp[++t]=P[i];
        }
        for(Re i=1;i<=t;++i){
            LD k=-sqrt((LD)cp[i].y/cp[i].x);
            if((i==1||dcmp(k-getk(cp[i],cp[i-1]))<=0)&&(i==t||dcmp(k-getk(cp[i],cp[i+1])>=0)))ans=min(ans,calc(cp[i],k));
            if(i>1)ans=min(ans,calc(cp[i],getk(cp[i],cp[i-1])));
            if(i<t)ans=min(ans,calc(cp[i],getk(cp[i],cp[i+1])));
        }
        printf("%.4lf\n",ans);
    }
    
    • 1

    信息

    ID
    2364
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者