AOJ 2434 Audition

解法

他のそれぞれのアイドルの得点の期待値は,3種類の要素の得点の確率変数をX, Y, Z とすると E[X + Y + Z] だが,これは期待値の線形性から E[X] + E[Y] + E[Z] と等しい.
したがって,それぞれの要素は独立に計算して良い.
すると以下の DP が生える.

dp[i][j][k] := i 人目のアイドルまで見て,担当アイドルが j 回その要素でアピールしたときに,担当アイドルが k 位になる確率

トップ3か最下位しか興味がなく,最下位は簡単に(分けて)求められるので,k = 0, 1, 2, worst の4種類だけ考えれば良い.

それぞれの要素についてこの dp テーブルを求めたら,あとは回数の振り分けを O(m^2) でやって,一番いいやつを選ぶ.この部分は O(m) にもできるけどやる必要はない.

ソースコード

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

int main() {
    int n, m;
    cin >> n >> m;
    vector<int> vi(n), da(n), vo(n);
    for(int i = 0; i < n; ++i) {
        cin >> vi[i] >> da[i] >> vo[i];
    }

    vector<double> p(m + 1, 0);
    p[0] = 1;
    for(int i = 0; i < m; ++i) {
        vector<double> nxt(m + 1);
        for(int i = 0; i <= m; ++i) {
            nxt[i] += p[i] * 2 / 3.0;
            if(i != m) {
                nxt[i + 1] += p[i] / 3.0;
            }
        }
        p = move(nxt);
    }
    for(int i = 0; i < m; ++i) {
        p[i + 1] += p[i];
    }

    auto calc = [&](vector<int> const& v) {
        vector<vector<double>> dp(m + 1, vector<double>(4));
        for(int i = 0; i < m + 1; ++i) {
            dp[i][0] = dp[i][3] = 1;
        }
        for(int i = 1; i < n; ++i) {
            vector<vector<double>> nxt(m + 1, vector<double>(4));
            for(int j = 0; j <= m; ++j) {
                const int t = v[0] * j;
                const int cnt = (t + v[i] - 1) / v[i];
                const double win = p[min(m, cnt - 1)];
                for(int k = 0; k < 3; ++k) {
                    nxt[j][k] += (cnt == 0 ? 0 : dp[j][k] * win); // win
                    if(k + 1 < 3) {
                        nxt[j][k + 1] += (cnt == 0 ? dp[j][k] : dp[j][k] * (1 - win)); // lose
                    }
                }
                nxt[j][3] += dp[j][3] * (1 - win);
            }
            dp = move(nxt);
        }
        return dp;
    };
    auto dp1 = calc(vi);
    auto dp2 = calc(da);
    auto dp3 = calc(vo);

    double ans = -1e9;
    for(int i = 0; i <= m; ++i) {
        for(int j = 0; j + i <= m; ++j) {
            int k = m - i - j;
            double t = (dp1[i][0] + dp1[i][1] + dp1[i][2]) * 5;
            t += (dp2[j][0] + dp2[j][1] + dp2[j][2]) * 3;
            t += (dp3[k][0] + dp3[k][1] + dp3[k][2]) * 2;
            t -= (dp1[i][3] + dp2[j][3] + dp3[k][3]);
            ans = max(ans, t);
        }
    }

    cout << fixed << setprecision(10) << ans << endl;
}