洛谷P8208 [THUPC2022 初赛] 骰子旅行 题解 期望DP

题目链接: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;
}
posted @ 2024-09-13 12:54  quanjun  阅读(8)  评论(0编辑  收藏  举报