Skip to content

Stick lengths

Stick Lengths
CSES

Abridged problem statement

You are given an array aa of length nn. Choose an array cc such that a[i]+c[i]=a[j]+c[j]a[i]+c[i]=a[j]+c[j] for all (i,j)(i,j), and c[i]\sum|c[i]| is minimized.

Solution

Let’s fix the final value each a[i]a[i] ends up with: call this xx. Then, our goal is to choose an xx that minimizes a[i]x\sum|a[i]-x|.

Here’s a plot of the value of a[i]x\sum|a[i]-x| against xx for a=[0,1,4,5,7,10,12,13]a=[0,1,4,5,7,10,12,13]:

303438424650012345678910111213

We can make some inferences from this graph. To begin with, it looks like the graph decreases first, then becomes flat, and then increases. In addition to this, the minimum value seems to be attained at all values from x=5x=5 to x=7x=7.

Let us try generalising these observations. Define f(x)=xa[i]f(x)=\sum|x-a[i]|, and examine the value of f(x+1)f(x)f(x+1)-f(x):

  • Changing xx to x+1x+1 brings us closer to all a[i]>xa[i]>x.
  • It also brings us farther from all a[i]xa[i] \le x.

That is,

(x+1)aixai={+1aix1ai>x |(x+1)-a_i|-|x-a_i|= \begin{cases} +1 & a_i \le x \\ -1 & a_i > x \end{cases}

So, define c(v)={i;a[i]v}c(v)=|\{i; a[i] \le v\}|, then f(x+1)f(x)=c(x)[nc(x)]=2c(x)nf(x+1)-f(x) = c(x) - [n-c(x)] = 2c(x) - n. Therefore, f(x+1)<f(x)f(x+1)<f(x) when c(x)<n2c(x)<\frac{n}{2}. Since c(x)c(x) is an integer, this becomes c(x)n12c(x)\le\lfloor\frac{n-1}{2}\rfloor.

In other words, as long as there are less than n12\lfloor\frac{n-1}{2}\rfloor elements to our left, f(x+1)f(x+1) is better than f(x)f(x). After that, f(x+1)f(x+1) is worse (or just as good as) f(x)f(x). So we pick xx such that there are exactly n12\lfloor\frac{n-1}{2}\rfloor elements to the left of it in our array.

Such a value is called a median of the array. Hence, the minimum is attained when xx is a median of aa. If nn is even, every value between the two medians is optimal.

Code

#include <bits/stdc++.h>

using namespace std;

using int64 = long long;

int main() {
  int n;
  cin >> n;
  vector<int> a(n);
  for (int &i : a) {
    cin >> i;
  }
  sort(a.begin(), a.end());
  int64 ans = 0;
  for (int &i : a) {
    ans += abs(a[(n - 1) / 2] - i);
  }
  cout << ans << '\n';
}