Загрузка данных
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine().trim());
long[] h = new long[n + 1];
for (int i = 1; i <= n; i++) h[i] = Long.parseLong(st.nextToken());
long[] L = new long[n + 1];
long[] R = new long[n + 1];
for (int j = 1; j <= n; j++) {
L[j] = h[j] - j; // для левой группы: a[j] = L[j] + i
R[j] = h[j] + j; // для правой группы: a[j] = R[j] - i
}
// координатное сжатие
long[] all = new long[2 * n];
for (int j = 1; j <= n; j++) { all[j-1] = L[j]; all[n+j-1] = R[j]; }
Arrays.sort(all);
int sz = 0;
for (int i = 0; i < 2*n; i++)
if (i == 0 || all[i] != all[i-1]) all[sz++] = all[i];
int SZ = sz + 2;
int[] lcnt = new int[SZ+1]; long[] lsum = new long[SZ+1];
int[] rcnt = new int[SZ+1]; long[] rsum = new long[SZ+1];
int totL = 0, totR = n;
long sumLtot = 0, sumRtot = 0;
// изначально все в правой группе
for (int j = 1; j <= n; j++) {
int lo2 = 0, hi2 = sz;
while (lo2 < hi2) { int m = (lo2+hi2)/2; if (all[m] < R[j]) lo2=m+1; else hi2=m; }
int p = lo2 + 1;
for (int k = p; k <= SZ; k += k&-k) { rcnt[k]++; rsum[k] += R[j]; }
sumRtot += R[j];
}
long ans = Long.MAX_VALUE;
for (int i = 1; i <= n; i++) {
// убираем R[i] из правой группы
int lo2, hi2;
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<R[i]) lo2=m+1; else hi2=m; }
int p = lo2 + 1;
for (int k = p; k <= SZ; k += k&-k) { rcnt[k]--; rsum[k] -= R[i]; }
totR--; sumRtot -= R[i];
// добавляем L[i] в левую группу
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<L[i]) lo2=m+1; else hi2=m; }
p = lo2 + 1;
for (int k = p; k <= SZ; k += k&-k) { lcnt[k]++; lsum[k] += L[i]; }
totL++; sumLtot += L[i];
// бинпоиск медианы: ищем минимальное V, где count(a[j] <= V) >= (n+1)/2
// count(a <= V) = countLeft(L <= V-i) + countRight(R <= V+i)
long lo = -2_000_000_000L, hi = 2_000_000_000L;
while (lo < hi) {
long mid = lo + (hi-lo)/2;
// считаем сколько L[j] <= mid-i через фенвик
long target = mid - i;
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<=target) lo2=m+1; else hi2=m; }
int cntL = 0;
for (int k = lo2; k > 0; k -= k&-k) cntL += lcnt[k];
// считаем сколько R[j] <= mid+i
target = mid + i;
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<=target) lo2=m+1; else hi2=m; }
int cntR = 0;
for (int k = lo2; k > 0; k -= k&-k) cntR += rcnt[k];
if (cntL + cntR >= (n+1)/2) hi = mid; else lo = mid+1;
}
long med = lo;
long minH = Math.max(i-1, n-i) + 1;
// функция выпуклая, оптимум — медиана или граница minH
long[] cands = { Math.max(med, minH), Math.max(med-1, minH) };
for (long H : cands) {
long cost = 0;
// левая часть: sum |L[j] - (H-i)|
long P = H - i;
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<=P) lo2=m+1; else hi2=m; }
int cl = 0; long sl = 0;
for (int k = lo2; k > 0; k -= k&-k) { cl += lcnt[k]; sl += lsum[k]; }
cost += P*(long)cl - sl + (sumLtot-sl) - P*(long)(totL-cl);
// правая часть: sum |R[j] - (H+i)|
long Q = H + i;
lo2 = 0; hi2 = sz;
while (lo2 < hi2) { int m=(lo2+hi2)/2; if(all[m]<=Q) lo2=m+1; else hi2=m; }
int cr = 0; long sr = 0;
for (int k = lo2; k > 0; k -= k&-k) { cr += rcnt[k]; sr += rsum[k]; }
cost += Q*(long)cr - sr + (sumRtot-sr) - Q*(long)(totR-cr);
ans = Math.min(ans, cost);
}
}
System.out.println(ans);
}
}