Official

E - Sugoroku 4 Editorial by nok0


\(\mathrm{dp}[i][j]\) を、ルーレットを \(i\) 回回したときにマス \(j\) にいる確率と定義した動的計画法で解くことが出来ます。

遷移時に \(\text{mod } 998244353\) 上での \(\frac{1}{M}\) を計算する必要がありますが、低速な言語だと毎回これを計算していると間に合わないため、前計算しておく必要があります。

前計算を行った場合、動的計画法の状態数が \(\mathrm{O}(NK)\) 、各状態の遷移回数が \(\mathrm{O}(M)\) なので計算量は \(\mathrm{O}(NMK+ \log \mathrm{mod})\) (ここで \(\mathrm{mod}=998244353\)) です。

実装例(c++):

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

using mint = atcoder::modint998244353;

int main() {
    int n, m, k;
    cin >> n >> m >> k;
    vector dp(k + 1, vector(n + 1, mint(0)));
    mint m_inv = mint(1) / m;
    dp[0][0] = 1;
    for(int i = 0; i < k; i++) {
        for(int j = 0; j <= n; j++) {
            if(j == n) {
                dp[i + 1][j] += dp[i][j];
                continue;
            }
            for(int l = 1; l <= m; l++) {
                int nx = j + l;
                if(nx > n) nx = n - (nx - n);
                dp[i + 1][nx] += dp[i][j] * m_inv;
            }
        }
    }
    cout << dp.back().back().val() << endl;
}

posted:
last update: