Official

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: