关于此题CF2040E Control of Randomness 的一些总结[树形DP][概率DP]

传送门

题目大意:给定一棵树和q个询问,每个询问给定\(v,p\),表示一开始有p枚硬币,需要从顶点\(v\)走到顶点\(1\),假设当前走第\(i\)步,如果\(i\)是奇数,那么会朝着顶点\(1\)的方向走一步,如果是偶数,可以花费一枚硬币向顶点\(1\)方向走一步,否则会等概率地随机向任一当前节点所连顶点走一步,问从\(v\)走到\(1\)的期望步数。

思路:对于每个奇数步数很简单,而对于每个偶数步数的情况,我们需要推一下式子。假设当前要走的是第偶数步,并且当前所处节点的度是\(d\),根据期望计算公式,从当前节点向顶点\(1\)方向走的期望步数是

\(\displaystyle \lim_{m \to \infty }\sum_{k=1}^{m} \frac{1}{d}*\frac{d-1}{d}^{k-1}*(2k-1)\)

其中\((2k-1)\)表示走\((2k-1)\)步的情况。即,走\(1\)步的概率是\(\frac{1}{d}\),走\(2\)步的概率是\(\frac{1}{d}*\frac{d-1}{d}\)依次类推。

要求这个式子,我们先把它拆开:

\(\displaystyle \lim_{m \to \infty }(\sum_{k=1}^{m} \frac{1}{d}*\frac{d-1}{d}^{k-1}*2k - \sum_{k = 1}^{m}\frac{1}{d}*\frac{d-1}{d}^{k-1})\)

对于后半部分直接用等比数列求和公式即可求出是\(1\),而对于前半部分,由于

\(\sum_{k=0}^{\infty }r^{k}=\frac{1}{1-r}\)

我们对两边同时求导有

\(\sum_{k=0}^{\infty }kr^{k-1}=\frac{1}{(1-r)^{2}}\)

由于\(k\)\(0\)时,即左式第一项为\(0\),所以可以直接令左式从\(1\)开始。所以我们直接将\(\frac{d-1}{d}\)带入求得\(d^{2}\),再乘上\(\frac{2}{d}\)\(2d\),故上式结果为\(2d-1\)

代码:

#include<bits/stdc++.h>
    
using namespace std;
    
const long long mod = 998244353;
long long t;
const long long N = 2e5 + 10;
long long n,q,in[N],dep[N];
long long head[N],tot,ans,step;
bool flag;
struct node {
    long long v,next;
}cnt[N];
priority_queue<long long> vt;

void insert(long long u,long long v) {
    cnt[++tot].v = v;
    cnt[tot].next = head[u];
    head[u] = tot;
}

void dfs1(long long u,long long fa) {
    dep[u] = dep[fa] + 1;
    for(long long i = head[u];i;i = cnt[i].next) {
        if(cnt[i].v == fa) continue;
        dfs1(cnt[i].v,u);
    }
}

void dfs2(long long u,long long fa,long long tg) {
    if(u == tg) {
        flag = true;
        vt.push(1);
        step++;
        return;
    }
    for(long long i = head[u];i;i = cnt[i].next) {
        if(cnt[i].v == fa) continue;
        dfs2(cnt[i].v,u,tg);
        if(flag == true) {
            if(u != 1) {
                step++;
                if(step % 2 != 0) vt.push(1);
                else vt.push((2 * in[u] - 1) % mod);
            }
            return;
        }
    }
}
    
void solve() {
    for(long long i = 0;i <= n;i++) head[i] = dep[i] = in[i] = 0;
    for(long long i = 0;i <= tot;i++) cnt[i].v = cnt[i].next = 0;
    tot = 0;
    cin >> n >> q;
    for(long long u,v,i = 1;i < n;i++) {
        cin >> u >> v;
        insert(u,v);
        insert(v,u);
        in[u]++;
        in[v]++;
    }
    dfs1(1,0);
    for(long long v,p,i = 1;i <= q;i++) {
        cin >> v >> p;
        ans = flag = step = 0;
        dfs2(1,0,v);
        while(!vt.empty()) {
            if(vt.top() > 1 && p > 0)
                ans++,p--;
            else ans += vt.top();
            vt.pop();
            ans %= mod;
        }
        cout << ans << '\n';
    }
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin >> t;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-02-14 19:20  孤枕  阅读(19)  评论(0)    收藏  举报