公式
C - Except and Min 解説
by
C - Except and Min 解説
by
Nyaan
各クエリでは高々 \(K\) 個 \((K \leq 5)\) のボールを取り出して、残ったボールの最小値を答えます。
ここで、全てのボールを書かれた値 \(A_i\) の昇順に並べた列を考えます。そして、先頭 \(6\) 個のボールに注目します。すると、ボールを取り出した時に \(6\) 個の中には必ず取り出されていないボールが \(1\) 個残ります。なぜならば、先頭 \(6\) 個を取り出すためには最低 \(6\) 個のボールを取り出す必要がありますが、一度に取り出すのは最大 \(5\) 個までだからです。
よって、次の方針でこの問題を解くことが出来ます。
- 全てのボールを書かれた値 \(A_i\) の昇順に並べた列を考えた時に、先頭 \(6\) 個に来るボールを計算する。
- 各クエリでは先頭から順に「そのボールが取り出されたか?」を調べる。取り出されていない最初のボールが答えとなる。
1.について、先頭 \(6\) 個を取得する方法はいくつかありますが、\((A_i, i)\) の組をソートする方法が最も簡明です。先頭 \(6\) 個を挿入ソートの要領で管理する方法もあり、この方法だと計算量が \(\mathrm{O}(N)\) になる (ソートだと \(\mathrm{O}(N \log N)\) かかってしまう) ので計算量の面ではこちらに分があります。
いずれの方法でも計算量は全体で \(\mathrm{O}(N + Q)\) や \(\mathrm{O}(N \log N + Q)\) で解くことができて、十分高速です。
- 実装例(C++)
#include <algorithm>
#include <iostream>
#include <set>
#include <utility>
#include <vector>
using namespace std;
int main() {
cin.tie(0)->sync_with_stdio(0);
int N, Q;
cin >> N >> Q;
vector<pair<int, int>> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i].first;
A[i].second = i;
}
sort(begin(A), end(A));
while (Q--) {
int K;
cin >> K;
vector<int> B(K);
for (auto& b : B) cin >> b;
for (int i = 0;; i++) {
if (find(begin(B), end(B), A[i].second + 1) != end(B)) continue;
cout << A[i].first << "\n";
break;
}
}
}
投稿日時:
最終更新:
