ICPC 2022济南 C:DFS Order 2 题解(回退背包)
C:
题意:给你一棵以1为根的树,输出一个n方的矩阵,即:第 i 行第 j 列表示在所有的DFS序中,第 i 个点出现在第 j 个位置的次数。(n<=500)
Solution:
透过样例我们可以看出父亲结点的那一行要比子结点的数字靠前,因为所有的DFS序都是访问完父亲再访问儿子,于是每棵子树其实可以看做一个子问题:我们只需要求出,每个子结点在它父亲这棵子树内DFS序的位置,然后再从父亲那一行的答案推导出自己的答案。
具体的,设 表示 u 在它父亲这棵子树内的DFS序为 i 的情况数。想要求出最后的答案 矩阵,就让父亲那一行的答案 平移乘上 数组,递归地向下求。
等于多少,即所有分叉处 siz 的阶乘。无论什么位置,不同的DFS序种数都是以阶乘计算。
接下来我们只需要求每个点的 f 数组,即每个点在父亲这棵树内排第几。
很容易想到一个背包的解法:
在DFS序中,每个子树都要先访问完才能跳出,若 u 排名为 i ,说明它前面先访问了大小和为 i-1 的兄弟子树,将每个兄弟树看做物品,背包求出装满 i-1 的空间有多少种方案,由于背包内的物品还可以交换位置,因此还要记录装了多少个物品,答案最终还要乘以物品数量的阶乘。
表示装了 i 棵子树,总大小为 j 的方案数,这样求出每个儿子的 都是 n^3 的复杂度,因为物品是 “所有的兄弟树”,自己这棵子树是不能算入物品的。
但是发现这题满足回退背包的科技前提:求的是方案数不是最值,而且所有儿子的转移是平等的。
每棵子树对 dp 数组的贡献无非就是加上自己这棵树大小的平移量,那么按原路再减回去,相当于没有加过自己这棵树。
这时所有的儿子只需要求一遍背包,计算 u 的 f 数组时再把 u 这棵子树的贡献从背包中回退,总复杂度变成 n^3。
至初学者:刚开始理解回退背包会比较发懵,自己放几个物品当例子手动写一下 dp 数组就会了。
然后写代码的时候还会发懵,这个回退过程不仅要把加号变成减号这么简单,还需要完全原路返回,包括滚动优化时的枚举顺序,以及贡献传递的方向,才能保证回退不出问题。
__EOF__

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具