AOJ 2294 Entangled with Lottery

解法

ゴールから見るDPでやります.

dp[i][j][k] := 高さ (H から) i まで見た時に,位置 j にいて,それまでに猫が k 本引いているような確率

とします.
高さ 1 から i までに,うさぎがすでに引いている本数を m とすると,猫が引ける高さは残り i - m 箇所です.
今見ている高さがすでにうさぎによって線が引かれていれば,単純に swap するだけです.
引かれていないなら,今見ている高さに猫が線を引く確率 q は,
$\displaystyle q = \frac{_{i - m - 1}C_{K - k - 1}}{_{i - m}C_{K - k}} = \frac{K - k}{i - m}$
となります.
引いた上で,今見ている位置 j に関係する部分に線が引かれる確率 p は,端ならば $\displaystyle p = \frac{1}{N - 1}$,端でなければ $\displaystyle \frac{2}{N - 1}$ です.
あとは,dp[i][j][k] を,「その高さに線をそもそも引かない」「その高さに線を引き,かつそれが j に関係する」「その高さに線を引き,かつそれが j に関係しない」場合の3つに遷移させるだけです.

ソースコード

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

using pii = pair<int, int>;

int main() {
    cout << fixed << setprecision(10);
    int H, N, P, M, K;
    cin >> H >> N >> P >> M >> K;
    P--;
    vector<int> sw(H, -1);
    for(int i = 0; i < M; ++i) {
        int a, b;
        cin >> a >> b;
        sw[a - 1] = b - 1;
    }

    vector<int> sum(H + 1);
    for(int i = 0; i < H; ++i) {
        sum[i + 1] = sum[i] + (sw[i] != -1);
    }
    vector<vector<double>> dp(N, vector<double>(K + 1));
    dp[P][0] = 1;
    double p = 1.0 / (N - 1);
    for(int i = H - 1; i >= 0; --i) {
        vector<vector<double>> nxt(N, vector<double>(K + 1));
        for(int j = 0; j < N; ++j) {
            for(int k = 0; k <= K; ++k) {
                if(dp[j][k] == 0) {
                    continue;
                }
                if(sw[i] == -1) {
                    double q = (double)(K - k) / (i + 1 - sum[i]); // put possibility
                    if(k == K) {
                        nxt[j][k] += dp[j][k] * (1 - q); // (1 - q) == 1
                    } else {
                        if(j != 0) {
                            nxt[j - 1][k + 1] += dp[j][k] * p * q;
                        }
                        if(j != N - 1) {
                            nxt[j + 1][k + 1] += dp[j][k] * p * q;
                        }
                        nxt[j][k] += dp[j][k] * (1 - q);
                        if(j == 0 || j == N - 1) {
                            nxt[j][k + 1] += dp[j][k] * q * (N - 2) / (N - 1);
                        } else {
                            nxt[j][k + 1] += dp[j][k] * q * (N - 3) / (N - 1);
                        }
                    }
                } else {
                    if(sw[i] == j) {
                        nxt[sw[i] + 1][k] += dp[j][k];
                    } else if(sw[i] + 1 == j) {
                        nxt[sw[i]][k] += dp[j][k];
                    } else {
                        nxt[j][k] += dp[j][k];
                    }
                }
            }
        }
        dp = move(nxt);
    }

    double res = 0;
    for(int i = 0; i < N; ++i) {
        res = max(res, dp[i][K]);
    }
    cout << res << endl;
}