• ICPC2021 济南 DArithmetic Sequence


    题目描述:


    大意:
    通过将某一项+1/-1的操作,将序列改成等差序列,问最小操作数。

    题目思路:

    假定公差\(~ x ~\)已知,考虑如何寻找一个最优的首项\(a_1\)使得将原序列变为等差序列的总代价最小,设 \(c_i=a_i-(i-1)*x\),即将根据每一项的值求出对应的首项。当首项已知,就能求出等差序列,那么总代价即为等差序列与原序列每一项差的绝对值之和。对于首项\(a_1 \geq c_i\)时,当\(a_1\)增加1,第\(i\)项产生的代价加1;对于首项\(a_1<c_i\)时,当\(a_1\)增加1,第\(i\)项产生的代价减1。由上述可知,首项与总代价之间应该是一个凹函数的关系,而最小值点就是 代价加1的项的数量=代价减1的项的数量 。那么我们选取\(c\)数组的中位数,可作为最优的首项。再求出总代价,即可。求解中位数用\(nth\_element\)\(O(n)\)的。

    考虑公差\(x\)与总代价之间的关系,证明搬运官方题解:

    对于单峰函数来说,三分求极值即可。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=2e5+5;
    const LL inf=2e18+5;
    LL a[N],n,c[N];
    __int128 __abs(__int128 x)
    {
        return x<0?-x:x;
    }
    __int128 Min(__int128 x, __int128 y)
    {
        return x<y?x:y;
    }
    __int128 check(LL x)//求总代价可能会爆longlong
    {
        for(int i=1;i<=n;i++) c[i]=a[i]-x*(i-1);
        nth_element(c+1,c+n/2+1,c+n+1);
        __int128 t=c[n/2+1],res=0;
        for(int i=1;i<=n;i++)
        {
            res+=__abs(t-a[i]);
            t+=x;
        }
        return res;
    }
    void print(__int128 x)
    {
        if(x>9) print(x/10);
        putchar('0'+x%10);
    }
    int main()
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;i++) scanf("%lld",a+i);
        LL l=-1e13,r=1e13;//等差既能递增,也能递减
        __int128 ans=1e25;
        LL x,y;
        while(l<=r)
        {
            LL m1=l+(r-l)/3;
            LL m2=r-(r-l)/3;
            __int128 t1=check(m1);
            __int128 t2=check(m2);
            ans=Min(ans,Min(t1,t2));
            if(t1>t2) l=m1+1;
            else r=m2-1;
        }
        print(ans);
        printf("\n");
        return 0;
    }
    
    
  • 相关阅读:
    【笔记】各种容器的特点
    超简单的java动态代理
    Mac idea 设置gitlab项目commit用户直见文尾有最优解
    burnside引理和polya定理
    最短路模板
    求phi及一些基本模板
    Unittest
    Pytest
    网络原因造成应用访问无响应
    CentOS7 下 离线安装 supervisor
  • 原文地址:https://www.cnblogs.com/DeepJay/p/15558041.html
Copyright © 2020-2023  润新知