Official

D - 相対評価のスコア/Relative Score Editorial by MMNMM


1. 整数の計算のみで求める方法

多くのプログラミング言語には、「正の整数 \(a,b\) について、\(\dfrac ab\) を超えない最大の整数を求める」方法があります。 例えば、C++ では a / b 、Python では a // b 、Haskell では div a b のように書くことができます。
これを用いて整数への四捨五入を行うことを考えます。

\(x\) を四捨五入して整数にしたものは、\(x+0.5\) を超えない最大の整数と等しいです(\(x\) を適当な半整数(たとえば \(1.5\) )の近くなどで動かしてみて「 \(x+0.5\) を超えない最大の整数」がどのようになるか観察してみるとよいでしょう)。 よって、\(\dfrac ab\) を四捨五入して整数にしたものは、\(\dfrac ab+\dfrac12=\dfrac{2a+b}{2b}\) を超えない最大の整数と等しいです。

あとは、これを用いて答えを計算することができます。

実装例は以下のようになります。 \(10 ^ 9A _ i\) が \(32\operatorname{bit}\) 整数の範囲に収まらない場合があることに注意してください。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;
    cin >> N;

    vector<int> A(N);
    for (auto&& a : A)
        cin >> a;

    int max_A = ranges::max(A);
    for (const auto a : A)
        // 1000000000 * a / max_A を四捨五入した整数 <=> (2000000000 * a + max_A) / (2 * max_A) を超えない最大の整数
        cout << (2000000000L * a + max_A) / (2 * max_A) << " ";
    cout << endl;

    return 0;
}
N = int(input())
*A, = map(int, input().split())

max_A = max(A)

for a in A:
    print((2000000000 * a + max_A) // (2 * max_A))

2. 小数の計算を経由する方法

いくつかのプログラミング言語には、四捨五入をする関数がある場合があります。 例えば、C++ には( cmath ヘッダに) std::round 関数があります。

この関数を使って \(10 ^ 9\dfrac{A _ i}{\max _ iA _ i}\) を直接四捨五入することでこの問題を解くこともできます。

実装例は以下のようになります。
Python の round は四捨五入ではない(偶数への丸めを行う)ので注意してください。
適切な精度の浮動小数点数を使って 1000000000.0 * a / max_A の順に計算を行うとそのまま四捨五入を行っても正しい答えを得ることができますが、そうでない順序にすると計算誤差の分を補正する必要が生じることに注意してください。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

int main() {
    int N;
    cin >> N;

    vector<int> A(N);
    for (auto&& a : A)
         cin >> a;

    int max_A = ranges::max(A);
    for (const auto a : A)
        cout << int(round(1000000000.0 * a / max_A)) << " ";
    cout << endl;

    return 0;
}

posted:
last update: