P10789 [NOI2024] 登山

打印 上一主题 下一主题

主题 850|帖子 850|积分 2550

思路:

我们可以对于每个 \(i\) 找到它能跳到的最远的点和近来的点,倍增求一下 \(k\) 级祖先即可,令 \([l_i,r_i]\) 新表示 \(i\) 能跳到其祖先中深度在 \([l_i,r_i]\) 内的点;同时令 \(lim_i = d_i - h_i-1\) 表示 \(i\) 至少要跳到 \(lim_i\) 的深度。
考虑动态规划算法,令 \(dp_i\) 表示从 \(i\) 出发到山顶的合法登山序列个数。
那么相当于先从 \(i\) 滑落到 \(j\),然后再从 \(j\) 冲刺到 \(k\),再加上 \(dp_k\) 的方案数。
则状态转移方程为:

\[dp_i = \sum_{j 在 i 子树内} \sum_{k 为 i 的祖先} (d_k \in [l_j,\min(W(i,j),r_j)]) dp_k\]
其中 \(W(i,j)\) 表示 \(i \to j\) 路径上 \(lim_k\) 的最小值,由于每次冲刺到达的深度必须小于所有颠末的点的 \(lim_k\)。
质朴实现是 \(O(N^3)\) 的,考虑优化;注意到 \(k\) 是 \(i\) 的祖先中一段深度连续的点,则我们可以做一个深度的 \(dp_i\) 的前缀和,差分即可,时间复杂度优化至 \(O(N^2)\),可以得到 25pts。
$O(N^2)$ Code: [code]namespace Sub1{    ll L,R,x,a,b;    ll s[N],dp[N],dep[N];    void dfs1(ll u){        for(auto v:E){            if(v==fa)              continue;            dep[v]=dep+1;            dfs1(v);        }    }    ll get(ll l,ll r){        if(!l)          return s[r];        return (s[r]-s[l-1]+mod)%mod;    }    void dfs3(ll u,ll Min,ll from){        L=l,R=min(r,Min);        if(L1;        build(k
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表