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: