题解
首先我们看,对于一段区间[l,r],他们如果是递增的,那么最优解就是对于
z[i]=t[i],i∈[l,r]
,如果是递减的话那么最优解就是中位数了,即
z[i]=t[(l+r)/2],i∈[l,r]
如果我们把递增的区间拆成一个点一个点的,现在的序列就相当于有很多段递减的区间构成辣,那么现在的问题就是有很多段连续的区间,然后每段的答案都为一个值。我们考虑如何合并两段区间的答案.
假设我们要合并区间[l,n],[n+1,r]这两段区间,他们的最优解分别是{
u,u,u,⋯u
},{
u′,u′,u′,⋯u′
}
假设合并后答案为
{b[l],b[l+1],b[l+2],⋯b[n],b[n+1],b[n+2],b[n+3],⋯b[r]}
那么明显的,
b[n]<=u,b[n+1]>=u′
假如
b[n]>u
,那么我们可以将
{b[l],b[l+1],b[l+2],⋯b[n]}
变为{
u,u,u,⋯u
},显然更优,对于
b[n+1]>=u′
同理.
然后结合绝对值的几何意义,我们可以解改为
{b[n],b[n],b[n],⋯b[n],b[n+1],b[n+1],b[n+1],⋯b[n+1]}
当b[n+1]>u时,b[n]显然应该=u,而当b[n]=u时,显然b[n+1]=u时原式最小。当u’<=b[n+1]<=u时,显然b[n]等于b[n+1]时原式最小,综上所述原式最小时b[n]一定等于b[n+1],当b[n]=b[n+1]=w时,原式最小(w为两段序列的中位数)。那么合并后的两段区间的解变为
{w,w,w,⋯w,w,w,w,⋯w}
然后现在一个很容易想到的做法是用平衡树来维护中位数,复杂度两个log.
然后我们发现,按照上面的合并方式的话,我们也可以把递减的序列拆成一个一个的,我们可以把问题转化成一个元素一个元素的加入,维护单调的一个当前的解集。然后我们看加入一个元素后两段区间A,B被合并的情况,很显然当加入这个元素前, AmidA<BmidB 然后加入后 AmidA>Bmid′B (这样他们才有可能被合并),这就说明 BmidA 一定大于 max{x,BmidB−1} 即 BmidA 一定是两段序列中的第 midA+midB 大的数,那么 midA,midB 的奇偶进行简单的讨论一下后,会发现如果我们直接维护的A序列前 midA 个数和B序列前 midB 个数的话,然后将这些数合并的话,新序列C的前 midC 个数一定出现且仅出现在这里面。所以我们可以对每一个序列维护前mid个数就ok了
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N = 1e6 + 9;
int n;
void G (int &num) {
static char a; static bool fl;
for (a = getchar (), fl = false; a > '9' || a < '0'; a = getchar ()) if (a == '-') fl = true;
for (num = 0; a >= '0' && a <= '9'; a = getchar ()) num = (num << 3) + (num << 1) + a - '0';
if (fl) num = -num;
}
void IO () {
freopen ("1367.in", "r", stdin);
freopen ("1367.out", "w", stdout);
}
struct LT {
int data, dist, size;
LT *l, *r;
void set () { data = dist = size = 0; l = r = this; }
void update () { dist = r -> dist + 1; size = l -> size + r -> size + 1; }
LT () {}
LT (int x, LT *fl) : data (x), dist (1), size (1), l (fl), r (fl) {}
}*Null, *root[N], pool[N], *pis = pool;
LT* Merge (LT *A, LT *B) {
if (A == Null) return B;
if (B == Null) return A;
if (A -> data < B -> data) std :: swap (A, B);
A -> r = Merge (A -> r, B);
if (A -> l -> dist < A -> r -> dist) std :: swap (A -> l, A -> r);
A -> update ();
return A;
}
LT* newnode (int xxx) {
return new (pis++) LT (xxx, Null);
}
void Pop (LT *&x) {
x = Merge (x -> l, x -> r);
}
int t[N], x, top, c[N], w[N], l[N], r[N];
void Solve () {
Null = new (pis++) LT ();
Null -> set ();
G (n);
for (int i = 1; i <= n; ++i) {
scanf ("%d", &x); x -= i; w[i] = x;
root[++top] = newnode (x);
l[top] = r[top] = i;
c[top] = 1;
while (top > 1 && root[top] -> data < root[top - 1] -> data) {
--top;
root[top] = Merge (root[top], root[top + 1]);
if ((c[top] & 1) && (c[top + 1] & 1)) Pop (root[top]);
r[top] = r[top + 1];
c[top] += c[top + 1];
}
}
long long ret = 0;
for (int i = 1; i <= top; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
ret += abs (w[j] - root[i] -> data);
}
}
printf ("%lld\n", ret);
}
int main () {
// IO ();
Solve ();
return 0;
}