1 条题解

  • 0
    @ 2025-8-24 21:49:56

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar kczno1
    **

    搬运于2025-08-24 21:49:56,当前版本为作者最后更新于2017-02-02 11:10:45,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    题意应为使得max{|a(i)-a(i+1)|}最小。 二分答案del,

    之后从后往前扫一遍,如果a(i)-a(i+1)>del就把a(i)减掉;

    再从前往后扫一遍,如果a(i)-a(i-1)>del就把a(i)减掉。

    现在考虑如何使得存在a(k)=0。

    假如枚举k,那么使a(k)=0后,

    相当于在(k,0)往左划了一条斜率=-del的直线,直线上方的都要被减掉。

    肯定是从a(k-1)开始往前往后影响,影响到a(l);

    同时往右划了一条斜率=del的直线,直线上方的都要被减掉。

    肯定也是从a(k+1)开始持续到一个a(r)。

    如果让这条直线单调往右,那么l,r也是单调往右的。

    维护这个l,r即可。

    #include<cstdio>
    
    #define ll long long
    #define N 1000100
    int a0[N],a[N];ll s[N]; 
    int n,i;ll m;
    
    int ok(ll del)
    {
        ll now=m,x;
        for (i=1;i<=n;++i) a[i]=a0[i];a[n+1]=-1;
        for (i=n-1;i;--i) 
        if ((x=a[i]-a[i+1]-del)>0)
        {
            a[i]-=x;now-=x;
        }
        if (now<0) return 0;
        for (i=2;i<=n;++i)
        if ((x=a[i]-a[i-1]-del)>0)
        {
            a[i]-=x;now-=x;
        }
        if (now<0) return 0;
        for (i=1;i<=n;++i) s[i]=s[i-1]+a[i];
        ll l=1,r=1;
        for (i=1;i<=n;++i)
        {
            x=a[i];a[i]=0;
            while (a[l]<del*(i-l)) ++l;
            while (a[r+1]>=del*(r+1-i)) ++r;
            a[i]=x;
            if (s[r]-s[l-1]-now<=(del*((i-l)*(i-l+1)+(r-i)*(r-i+1)>>1))) return i;    
        }
        return 0;
    }
    
    int main()
    {
        freopen("1.in","r",stdin);
        scanf("%d%lld",&n,&m);
        for (i=1;i<=n;++i) scanf("%d",a0+i);
        if (ok(0)) {printf("%d %d",ok(0),0);return 0;}
        int l=0,r=1e9+1;
        while (l+1!=r)//l is false r is ok
        {
            int mid=l+r>>1;
            if (ok(mid)) r=mid;
            else l=mid;
        }
        printf("%d %d",ok(r),r);
    }
    
    • 1

    信息

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