其实这是道水题啦……只不过我没作过而已node
先考虑构造不严格递增序列,考虑原序列中的一段降低区间,显然区间中的$z$全取中位数最优;ios
那么能够把原序列拆成不少个降低序列,从头至尾加入原序列中的数,每次把加进来的数当作一个新的降低区间,而后不断合并最后两个区间直到,最后一个区间的中位数不小于倒数第二个区间的中位数;spa
用可合并堆维护便可,左偏树啥的都行,我写的斜堆;code
可合并堆如何维护区间中位数?只保留较小一半的数,则堆顶就是中位数;blog
要构造严格递增序列只须要把原序列中的每一个数$t_i$减去$i$便可(显然我不会证);string
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std; 10 typedef long long ll; 11 typedef double db; 12 struct node{ 13 int ls,rs,v,siz; 14 }t[1000001]; 15 int n,cnt=0,num[1000001],rts[1000001],R[1000001]; 16 ll ans=0; 17 int merge(int x,int y){ 18 if(!x||!y)return x|y; 19 if(t[x].v<t[y].v)swap(x,y); 20 t[x].siz+=t[y].siz; 21 t[x].rs=merge(t[x].rs,y); 22 swap(t[x].ls,t[x].rs); 23 return x; 24 } 25 int main(){ 26 scanf("%d",&n); 27 for(int i=1;i<=n;i++){ 28 scanf("%d",&num[i]); 29 num[i]-=i; 30 t[i].v=num[i]; 31 t[i].siz=1; 32 cnt++; 33 rts[cnt]=R[cnt]=i; 34 while(cnt>1&&t[rts[cnt]].v<t[rts[cnt-1]].v){ 35 R[cnt-1]=R[cnt]; 36 cnt--; 37 rts[cnt]=merge(rts[cnt],rts[cnt+1]); 38 while(t[rts[cnt]].siz*2>R[cnt]-R[cnt-1]+1){ 39 rts[cnt]=merge(t[rts[cnt]].ls,t[rts[cnt]].rs); 40 } 41 } 42 } 43 for(int i=1,j=1;i<=cnt;i++){ 44 for(;j<=R[i];j++){ 45 ans+=abs(t[rts[i]].v-num[j]); 46 } 47 } 48 printf("%lld\n",ans); 49 return 0; 50 }