[BalticOI 2004]Sequence

一、題目

點此看題

二、解法

第一步可以把aia_ibib_i都減去ii,結果不會變,但是單調遞增就變成了單調不減。

考慮xa+xb|x-a|+|x-b|之類的問題最優解就是取中位數(我們默認選後面那位),我們可以把原序列劃分成若干的子序列,每一個子序列的中位數就是局部的最優解,需要滿足單調不減。我們用可並堆維護中位數,我們每次加入一個點,當 前一個序列的中位數大於後一個序列的中位數,那麼就暴力合併,時間複雜度O(nlogn)O(n\log n)

#include <cstdio>
#include <iostream>
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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章