| x - a | + | x - b | + | x - c | + ...
の最小値を求める問題には定石があるぞいぞい
問題概要
長さ の整数列 が与えられます。整数 をいろいろ変えたときの
の最小値を求めてください。
制約
考えたこと
非本質だけど、 って普通「変数」じゃなくて「定数」に使う記号じゃん。なので、紛らわしいので じゃなくて にしてみよう。(非本質なんだけど、こういうの意外と大事だと思う)。
そして、この式だと、数列 が主役っぽくなっているので、 を主役に書き換えてみます。 であることから、こんな風に書き換わります
だいぶ見やすくなった。さらに、 とすると
となります。かなり見やすくなった。ここまできたら、もう知っている人は知っていると思う!!!
絶対値の和の最小化
結論からいうと、
を最小にする は、 のメディアンになります!!!
その証明は、ここにも書きました。
結論
答えは、
- とおいて
- を のメディアンとして、
- の値を求める
とすればよい。計算量は、メディアンを求めるのにソートすることから、 となる。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int N; cin >> N; vector<long long> A(N), B(N); for (int i = 0; i < N; ++i) cin >> A[i], B[i] = A[i] - i; // メディアンを sort(B.begin(), B.end()); long long x = B[N/2]; // 答えを求める long long res = 0; for (int i = 0; i < N; ++i) { res += max(x - B[i], -x + B[i]); // |A| = max(A, -A) } cout << res << endl; }