C - Standings Editorial by nok0
まず、二人の人の成功率を比較する関数を設計しましょう。ここで、問題文で言われた通りに \(\frac{A_i}{A_i+B_i}\) と \(\frac{A_j}{A_j+B_j}\) の大小を浮動小数点型を用いて比較するのは、誤差の関係上危険です。実際、double
を用いた大小比較による解法は落ちるケースが複数入っています。
ここでは、\(\frac{A_i}{A_i+B_i}<\frac{A_j}{A_j+B_j}\) の分母を払ってあげて、\({A_i}{(A_j+B_j)}<{A_j}{(A_i+B_i)}\) かどうかを判定することにすれば、整数型を用いて大小比較をすることができます。(なお、 \({A_i}{(A_j+B_j)}\) は 32bit 整数型に収まらないため 64bit 整数型を用いる必要があります。)
以上のように設計した関数を、標準ライブラリなどのソート関数に渡してあげればよいです。しかし、あと一つ注意点があります。これは、 C++ の標準ライブラリ std::sort
は安定ソート(Wikipedia)でないことです。そのため、比較関数が同率の場合ソートの前後で順序が入れ替わってしまう可能性があります。
この解決策としては、安定ソートであるstd::stable_sort
を用いるか、\({A_i}{(A_j+B_j)}={A_j}{(A_i+B_i)}\) の場合 \(i<j\) であるかという判定を比較関数に加えればよいです。
実装例(C++):
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> ab;
for(int i = 0; i < n; i++) {
int a, b;
cin >> a >> b;
ab.emplace_back(a, a + b);
}
vector<int> p(n);
iota(p.begin(), p.end(), 0);
auto f = [&](int i, int j) {
auto [ai, aj] = ab[i];
auto [bi, bj] = ab[j];
return (long long)ai * bj > (long long)aj * bi;
};
stable_sort(p.begin(), p.end(), f);
for(int i = 0; i < n; i++) cout << p[i] + 1 << " \n"[i == n - 1];
}
posted:
last update: