[NOIP2022] 建造军营

前言#

米奇妙妙 dp , 也是高端计数

这种题看得懂想不出, 还是非常难蚌

能不能多想想再去看 TJ

算法#

思路 1#

注意到除了割边, 其他的边都没有影响, 显然可以缩 e-DCC 再进行处理

这里发现缩完之后形成一棵树, 考虑树形 dp

这里我有一个误区, 就是答案必须要是几个 dpx 组合到一起, 但是实际上完全不用
对于树这种特殊结构, dproot 已经包含了所有情况

因此令 dpx,0/1 表示只在 x 的子树之内建造军营, 军营的
首先考虑答案式子, 我们注意到, 答案应该是多种情况累加, 因为 dpx,1 实际上是不重不漏的, 主要需要处理的是那些无关紧要的边, 我们选择守或者不守
注意到如果缩完点之后当前子树的大小为 Sizex , 我们就有 Sizex1 条割边要守, 其中子树外的 mSizex+1 条边可以任选
这里有一个超级巨大的问题: 对于当前节点到父节点的边, 一定不能选, 因为对于父节点, dpdpa,1 实际上考虑了这条边, 选上之后会导致重复, 因此记录答案时不能算这条边

事实上如果最早就有关于答案式的思路, 可以通过手推样例/观察性质发现这种性质, 但是我还是大为震撼

所以答案为

i=1,irootndpi,1×2mSizex+dproot,1×2mSizex+1

太有实力啦

考虑递推

首先我们需要知道, 如果对于 x 的子树 son , 其中 son 内部有军营, 那么 xson 这条边必须要守, 其他无所谓

所以有

dpx,1dpson,1×dpx,0

dpx,1dpson,1×dpx,1

dpx,0dpx,0×dpson,0×2

dpx,1dpx,1×dpson,0×2

初始化

dpx,01,dpx,12Sizx1

注意这里表示的是只选 x 这一 e-DCC 中点的可能性, 反正可以随便选, 边随便选的情况在计算答案时统计


思路 2#

考虑复习

感觉之前的做法过于巧妙, 遂决定重新理解一种更一般的做法

简化问题#

首先理解题意

求选出点集 S 和边集的方案数, 使得任意切断边集中的一条边, 点集中的点仍然联通

你发现如果切掉的不是割边, 一定没有用, 所以考虑先缩成一棵树, 这样留下来的边才有讨论价值
注意这样做会多出来一个 2|E|ϵ 的系数, 其中 ϵ 表示割边的条数, 其意义是非割边随意保护或者不保护
还需要注意的是, 现在的一个点可能在原图中表示多个点, 这个再计算时是需要处理的
以下用 ε 表示该点在原图中代表多少点, μ 表示该点在原图中包含了多少条边

好的, 经过上面的转换, 我们只需要解决这个问题的树上版本, 不难想到树形 dp

分类讨论 + 转移#

dpu,0/1,0/1 表示对于 u 子树, 子树内是否有 S 中的点, 子树外是否有 S 中的点
第二个 0/1 方便合并时处理 uv 的边是否被保护

dpu,0,0dpu,0,1 的转移

不难发现

dpu,0,0dpu,0,0×2dpv,0,0dpu,0,1dpu,0,1×2dpv,0,1

表示 uv 可选可不选的方案数
最后处理 u 不选的方案数

dpu,0,0dpu,0,0×2εdpu,0,1dpu,0,1×2ε

dpu,1,0 的转移

你发现其必然可以从 dpu,0,0dpu,1,0 合并而来, 具体的

dpu,1,0dpu,0,0×dpv,1,0dpu,1,0dpu,1,0×dpv,1,1

合并最后处理

dpu,1,0dpu,0,0×(2ε×2μ2ε)dpu,1,0dpu,1,0×(2ε×2μ)

分别表示 u 被选和可选可不选5

你发现这样子, 第三维的 0/1 会爆炸, 所以特殊转移
gu,0/1 表示确定合并的时候要选 vw, fu,0/1 表示确定合并的时候不选 vw , 第二维意义不变

不难有

fu,0,gu,0dpu,0,0 fu,1fu,0×2dpv,1,0gu,1gu,0×dpv,1,1gu,1gu,1×dpv,1,1

最终

dpu,1,0fu,0×(2ε+μ2ε)dpu,1,0gu,1×(2ε+μ2ε)dpu,1,0fu,1×(2ε)

dpu,1,1 的转移

你发现这种情况下, 无所谓 u 点选不选择, 对于 v 子树中包含 S 中的点的情况, 都必须要选上 uv

dpu,1,1dpu,0,1×dpv,1,1dpu,1,1dpu,1,1×dpv,1,1

合并最后处理

dpu,1,1dpu,0,1×(2ε×2μ2ε)dpu,1,1dpu,1,1×(2ε×2μ)


太乱了, 写了很久也不能用, 显然需要更具体一点, 上面的也不一定正确

合并子树 (不考虑 u 节点)#

dpu,0,0dpu,0,1

不难发现

dpu,0,0dpu,0,0×2dpv,0,0dpu,0,1dpu,0,1×2dpv,0,1

dpu,1,1

不难发现

dpu,1,1dpu,0,1×dpv,1,1+dpu,1,1×dpv,1,1

dpu,1,0

这个唯一比较复杂

首先是分成很多种情况

  • 没选 u
    • 只选一棵子树 (此时 u 肯定不选)
      考虑记这种情况的方案数为 f0/1 表示是否选了子树
      转移类似 dpu,1,1

      f0dpu,0,0f1f1+f0×2dpv,1,0

      需要注意的地方是, 初始化 f0 时使用的 dpu,0,0 应当是还没有被更新的

      然而你发现这样子「確有問題」, 具体在于除了最后一颗子树, 其他子树的系数 f0 都不能表示「其他子树不选」, 所以我们需要对其进行修改
      观察 dpu,0,0 的转移式, 我们考虑计算出 C=vson(u)2dpv,0,0
      转移变为

      f1f1+C2dpv,0,0×2dpv,1,0

      进一步的, 直接令 f 表示 f1

      ff+Cdpv,0,0×dpv,1,0

    • 所有选了点的子树都和 u 有连边 (此时 u 不选) , 至少选两棵子树
      这种情况只能正难则反, 考虑减去不合法的情况, 即减去一个都没选的方案数, 再减去只选了一个的方案数, 同上转移, 仅仅把系数 2 去掉即可, 还有把第三维改成 1

  • u
    • 所有选了点的子树都和 u 有连边 (此时 u)
      每个儿子可以任意选或者不选

实现#

框架#

先计算各个边双联通分量的信息, 建好树之后如上开跑即可

代码#

在此之前先用数据验证算法正确性

总结#

神秘计数方法

dp 式子考虑不到的, 可以在统计答案时考虑

注意计数不重不漏, 注意初始化


连通性问题常常要往缩点计数类的方向去想
缩点计数类问题一定要注意缩点带来的系数

一种合并类问题, 具体的套路在 之后的一篇文章 中有提到, 不在这里赘述

善于运用辅助数组避免新开一维或者更复杂的讨论

分类讨论能力必须加强, 考虑清楚每一维的含义

posted @   Yorg  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示