AtCoder ABC 361 C - Make Them Narrow (4Q, 灰色, 250 点) - けんちょんの競プロ精進記録

けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 361 C - Make Them Narrow (4Q, 灰色, 250 点)

めっちゃ面白い問題!! 実はよく似た類題として次の問題がある!

atcoder.jp

問題概要

長さが  N の数列  A_{1}, A_{2}, \dots, A_{N} が与えられる。この数列から  K 個の要素を削除する。

残った数からなる数列中の、最大値と最小値の差の最小値を求めよ。

制約

  •  1 \le K \lt N \le 2 \times 10^{5}

考えたこと

 K 個削除する」というのは、「 N-K 個選び出す」と捉えた方が考えやすいので、そう考えることにしよう。改めて  W = N - K とおく。

直観的には、数列  A をソートした場合において、「連続する  W 個を選ぶ」とする場合にみ考えればよいと思われる。このことを一応検証してみよう。数列  A はソート済みであるとしよう。

数列  A から選ぶ要素のうちの最小値  v を固定して考えてみるとハッキリする。このとき、 A から  W 個選んだときの最大値をなるべく小さくしたい。そうすると、 v からスタートして小さい順に  W 個選べばよいことがわかる。

まとめると、 A を小さい順に並べた上で、 A_{i + W - 1} - A_{i} の値の最小値を求めればよい。計算量は  O(N \log N) となる。

コード

#include <bits/stdc++.h>
using namespace std;

int main() {
    int N, K;
    cin >> N >> K;
    vector<long long> A(N);
    for (int i = 0; i < N; ++i) cin >> A[i];
    
    sort(A.begin(), A.end());
    long long res = A.back() - A[0];
    for (int i = 0; i + (N - K) - 1 < N; ++i) {
        long long diff = A[i + (N - K) - 1] - A[i];
        res = min(res, diff);
    }
    cout << res << endl;
}