一、題目
二、解法
第一步可以把和都減去,結果不會變,但是單調遞增就變成了單調不減。
考慮之類的問題最優解就是取中位數(我們默認選後面那位),我們可以把原序列劃分成若干的子序列,每一個子序列的中位數就是局部的最優解,需要滿足單調不減。我們用可並堆維護中位數,我們每次加入一個點,當 前一個序列的中位數大於後一個序列的中位數,那麼就暴力合併,時間複雜度。
#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);
}