题目:
给出一棵 n 个点的树,求对于每个点 i 的 d(i) 值。
d(i)=i≠j∑1≤j≤ndist(j,i)k
1≤n≤50000,1≤k≤150
题解:
首先对于第二类斯特林数有一个性质:
nk=k∑i=0{ki}(ni)i!
这个性质很显然。nk 表示将 k 个球放入 n 个盒子。
然后枚举 k 个球放入盒子的盒数,即 i。然后将 k 个球放入 i 个盒子里,每个盒子非空,即为 {ki}。然后从 n 个盒子中选出 i 个盒子又有 (ni) 种,又因为盒子不同所以还要再乘上 i!。
对于题目所求的式子,我们不妨将这个性质代入 dis(x,i)k,得
d(i)=i≠j∑1≤j≤nk∑l=0{kl}(dist(x,l)l)l!=k∑l=0l!{kl}i≠j∑1≤j≤n(dist(x,l)l)
然后题目的 k 非常小,所以对于 k∑l=0l!{kl} 你可以随便搞暴力,反正 l! 和 {kl} 都可以预处理出来嘛。
因为 k 实在是太小了,所以你甚至用 {nm}={n−1m−1}+m{n−1m} 递推式 O(k2) 都可以过。
然后观察剩下的。
不妨考虑 dp 转移,设 u∈tri 表示 u 在 i 的子树内,u∈soni 表示 u 是 i 的其中一个儿子,那么设
dpi,j=∑u∈tri(dist(i,u)j)
根据组合数最基本的式子,
(nm)=(n−1m)+(n−1m−1)
有
dpi,j=∑u∈soni(dist(i,u)−1j)+(dist(i,u)−1j−1)
即
dpi,j=∑u∈sonidpu,j+dpu,j−1
然后换根 dp,即上一次转移中的父亲成为这次转移中的儿子,最后一直推下去即可。
总的时间复杂度分两块:
- 预处理第二类斯特林数和阶乘,O(k2)(这里是用递推式来做的)
- 换根 dp,O(nk)
总时间复杂度为 O(nk+k2)。
本文作者:trsins
本文链接:https://www.cnblogs.com/trsins/p/15776593.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步