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

传送门

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

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

limmk=1m1dd1dk1(2k1)

其中(2k1)表示走(2k1)步的情况。即,走1步的概率是1d,走2步的概率是1dd1d依次类推。

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

limm(k=1m1dd1dk12kk=1m1dd1dk1)

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

k=0rk=11r

我们对两边同时求导有

k=0krk1=1(1r)2

由于k0时,即左式第一项为0,所以可以直接令左式从1开始。所以我们直接将d1d带入求得d2,再乘上2d2d,故上式结果为2d1

代码:

#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 @   孤枕  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
山不在高,有仙则名。水不在深,有龙则灵。
点击右上角即可分享
微信分享提示