题解:AT_arc185_d [ARC185D] Random Walk on Tree
题目大意:根上挂了 \(n\) 条长为 \(m\) 的链,从根开始,每次随机选择和当前点直接相连了点并走过去,求期望多少步后能走每个点至少一次。
设 \(f_i\) 表示当前走到第i层,期望还需要多少步能走完一条链(到达链底)。
可以列出方程:\(f_i=\left\{ \begin{array}{rcl} f_1+1 & i=0 \\ \frac{f_{i-1}+f_{i+1}}{2}+1 & 1 \leq i <m \\ 0 & i=m \end{array}\right.\)
不难推出 \(f_{m-i}=\frac{i}{i+1} f_{m-i-1}+i\),所以 \(f_1=\frac{m-1}{m} f_0+m-1\),又有 \(f_0=f_1+1\),所以 \(f_0=m^2\)。
同理从链底走到根节点期望也是 \(m^2\) 步。
走完 \(n-i\) 条链后,由于走的方式是随机的,所以可以理解为在 \(n\) 条链中随机找一条来走,走对的概率是 \(\frac{i}{n}\) 的,所以期望要走 \(\frac{n}{i}\) 次。
注意到最后一次走完不用回到根节点,所以答案为 \((2\sum\limits_{i=1}^n \frac{n}{i}-1)m^2\)。
Code:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cassert>
#include<vector>
#include<cmath>
#include<cstring>
#include<set>
#include<climits>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10, MOD = 998244353;
long long ny[N];
int n, m;
int main(){
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
ny[0] = ny[1] = 1;
for(int i = 2; i <= n; i++)
ny[i] = (MOD - MOD / i) * ny[MOD % i] % MOD;
long long sum = 0, t = 1ll * m * m % MOD;
for(int i = n; i; i--){
sum = (sum + n * t % MOD * 2 % MOD * ny[i] % MOD) % MOD;
}
sum = (sum - t + MOD) % MOD;
cout << sum << "\n";
}