題目連結:https://www.luogu.com.cn/problem/P8208
解題思路:
定義 \(d_u\) 表示節點 \(u\) 的出度,定義 \(V_u\) 表示節點 \(u\) 一步能夠走到的節點的集合。
定義狀態 \(p_{u, c, v}\) 表示從節點 \(u\) 出發走恰好 \(c\) 步的情況下,至少經過一次節點 \(v\) 的機率。
則:
- 若 \(v = u\),則 \(p_{u, c, v} = 1\);
- 否則,若 \(c = 0\),則 \(p_{u, c, v} = 0\);
- 否則,\(p_{u, c, v} = \frac{1}{d_u} \sum\limits_{x \in V_u} p(x, c-1, v)\)
定義 \(f_{u, c}\) 表示從節點 \(u\) 開始走恰好 \(c\) 步,廢話指數的期望值,則:
- 若 \(c = 0\),則 \(f_{u, 0} = 0\);
- 否則,\(f(u, c) = \frac{1}{d_u} \sum\limits_{v \in V_u} f(v, c-1) + v \times p(v, c-1, u)\)
注:這道題目的意思有點繞 如果是從 \(u\) 先走到 \(v\),然後再繞回 \(u\),則額外增加的代價是 \(v\),而不是 \(u\)。所以會看見,上式中額外增加的代價是 \(v\) 而不是 \(u\)。即標下劃線的部分:
\[f(u, c) = \frac{1}{d_u} \sum\limits_{v \in V_u} f(v, c-1) + \underline{v} \times p(v, c-1, u)
\]
這裡是 \(v\) 不是 \(u\)。
示例程式:
#include <bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
typedef long long ll;
void gcd(ll a , ll b , ll &d , ll &x , ll &y) {
if(!b) {d = a; x = 1; y = 0;}
else { gcd(b , a%b,d,y , x); y -= x * (a/b); }
}
ll inv(ll a , ll n = mod) {
ll d , x , y;
gcd(a , n , d, x , y);
return d == 1 ? (x+n)%n : -1;
}
ll p[105][105][105], f[105][105], d[105];
bool visp[105][105][105], visf[105][105];
vector<int> g[105];
int n, s, T;
ll dfsp(int u, int c, int v) {
if (v == u) return 1;
if (c == 0) return 0;
if (visp[u][c][v])
return p[u][c][v];
visp[u][c][v] = true;
ll res = 0;
for (auto x : g[u])
res += dfsp(x, c-1, v),
res %= mod;
res = res * inv(d[u]) % mod;
return p[u][c][v] = res;
}
ll dfsf(int u, int c) {
if (c == 0) return 0;
if (visf[u][c])
return f[u][c];
visf[u][c] = true;
ll res = 0;
for (auto v : g[u])
res += dfsf(v, c-1) + v * dfsp(v, c-1, u) % mod,
res %= mod;
res = res * inv(d[u]) % mod;
return f[u][c] = res;
}
int main() {
cin >> n >> s >> T;
for (int u = 1; u <= n; u++) {
cin >> d[u];
for (int j = 0; j < d[u]; j++) {
int v;
cin >> v;
g[u].push_back(v);
}
}
cout << dfsf(s, T) << endl;
return 0;
}