Typical DP Contest C - トーナメント

解法

まず各山について考える.たとえば,8人いるなら [0, 7], [0, 3], [4, 7], [0, 1], … などが各山にあたる.
ある山 X に属する個人が,X の中で優勝する確率と,次に X が対戦することになる山 Y の同様の確率が求まるとする.
すると,山 X と Y を統合した山 Z について,Z の中で X および Y に属する個人が勝利する確率を求めることができる.
これをループあるいは再帰で実装すればよい.

計算量は O(K * 2^(2K)).

ソースコード

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

double calc_prob(double r1, double r2) {
    return 1.0 / (1 + pow(10, (r2 - r1) / 400));
}

int main() {
    cout << fixed << setprecision(10);

    int k; cin >> k;
    vector<int> R(1 << k);
    for(auto& x : R) cin >> x;

    function<vector<double>(int, int)> solve = [&] (int l, int r) {
        if(r - l == 1) {
            return vector<double>{1.0};
        }
        vector<double> res(r - l);
        const int sz = (r - l) / 2;
        auto l_res = solve(l, l + sz), r_res = solve(l + sz, r);
        for(int i = 0; i < sz; ++i) {
            for(int j = 0; j < sz; ++j) {
                res[i] += calc_prob(R[l + i], R[l + j + sz]) * l_res[i] * r_res[j];
                res[j + sz] += calc_prob(R[l + j + sz], R[l + i]) * l_res[i] * r_res[j];
            }
        }
        return res;
    };

    for(auto&& ans : solve(0, 1 << k)) {
        cout << ans << endl;
    }
}