[BalticOI 2004]Sequence

一、题目

点此看题

二、解法

第一步可以把 a i a_i ai b i b_i bi都减去 i i i,结果不会变,但是单调递增就变成了单调不减。

考虑 ∣ x − a ∣ + ∣ x − b ∣ |x-a|+|x-b| xa+xb之类的问题最优解就是取中位数(我们默认选后面那位),我们可以把原序列划分成若干的子序列,每一个子序列的中位数就是局部的最优解,需要满足单调不减。我们用可并堆维护中位数,我们每次加入一个点,当 前一个序列的中位数大于后一个序列的中位数,那么就暴力合并,时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

贴一个巨佬的博客:https://blog.csdn.net/qq_42101694/article/details/105294249

#include 
#include 
using namespace std;
#define ll long long
const int M = 1000005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,m,ch[M][2],val[M],dis[M],rt[M],siz[M],e[M];
ll ans;
int merge(int x,int y)
{
    if(!x || !y) return x|y;
    if(val[x]<val[y]) swap(x,y);
    ch[x][1]=merge(ch[x][1],y);
    if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x]=dis[ch[x][1]]+1;
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    return x;
}
void adjust()
{
    while((e[m]-e[m-1]+1>>1)<siz[rt[m]])
        rt[m]=merge(ch[rt[m]][0],ch[rt[m]][1]);
}
int Abs(int x)
{
    return x>0?x:-x;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        val[i]=read()-i;
        m++;e[m]=rt[m]=i;siz[i]=1;
        while(m>1 && val[rt[m-1]]>val[rt[m]])
        {
            rt[m-1]=merge(rt[m-1],rt[m]);
            e[m-1]=e[m];
            m--;
            adjust();
        }
    }
    for(int i=1,j=1;i<=m;i++)
        for(;j<=e[i];j++)
            ans+=Abs(val[j]-val[rt[i]]);
    printf("%lld\n",ans);
    for(int i=1,j=1;i<=m;i++)
        for(;j<=e[i];j++)
            printf("%d ",val[rt[i]]+j);
}

你可能感兴趣的:(堆,贪心)