洛谷P8208 [THUPC2022 初賽] 骰子旅行 題解 期望DP

quanjun發表於2024-09-13

題目連結: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;
}

相關文章