P8867 [NOIP2022] 建造军营 Solution

更好的阅读体验戳此进入

题面

给定连通图,需要选定至少一个关键点,然后保护至少一条边,被保护的边不会被破坏,需要保证无论破坏哪条边都不会影响关键点之间的连通性。求方案数。

Solution

这题我感觉还是有点难度的,主要是细节很多,如果不是我写的太麻烦了的话,感觉评个紫应该比较合理(不过似乎洛谷上西西弗的题难度评级都偏低一些

首先这个题意读完应该就能想到 Tarjan 边双缩点吧,这个还是很显然的。如果在同一个边双里,那么无论删去这里面的任意哪条边都不会使方案不合法,所以可以直接进行 e-BCC 缩点,这样对于每一个 e-BCC 里,如果设其中的边数为 ξ,点数为 ϵ,那么只考虑这个 e-BCC 的话,如果不在其中设置关键点(军营)其方案数就是 2ξ,设置的话就是 2ξ×(2ϵ1)

然后同时不难发现因为图本身是连通的,所以进行 e-BCC 缩点之后原图就会变成一棵树,所以此时这个东西就很显然变成了一个 树形DP。或者说就是变成了 1214 的部分分,如果想通了树形 DP,再缩个点之后就直接可以切了。

考虑 DP,不难想到一个很显然的状态,设 dp(p,0/1) 表示考虑到点 p 所在子树,且其子树中是否设置关键点(军营)的合法方案数,且此时必须满足 p 子树的所有关键节点都和 p 连通,这个继续讨论下去就会发现如果不这样设定就无法转移了。

考虑转移,对于任意一个 p 的子节点 son,首先显然有:

dp(p,0)dp(p,0)×dp(son,0)×2

然后考虑 dp(p,1) 的转移:

  1. 如果从 dp(son,0) 转移,那么这条边(桥)就是可保护也可不保护,且 p 点必须设为关键点。
dp(p,1)dp(p,1)×dp(son,0)×2
  1. 如果从 dp(son,1) 转移,那么则需要考虑,对于 p 为关键点的,则桥必须被保护。
dp(p,1)dp(p,1)×dp(son,1)
  1. 同2,对于 p 不为关键点的,显然要从前面所有子树转移后的 dp(p,0) 转移而来,且此时这个桥也必须被保护,因为我们要保证子树的关键节点和 p 连通。
dp(p,1)dp(p,1)+dp(p,0)×dp(son,1)

同时注意对于这里的转移 dp(p,0/1),我们用到的都是上一次的 dp(p,0/1),这个东西可以直接类似滚动数组思想写一下,也就是先转移 dp(p,1) 然后 dp(p,0)

于是我们就发现,这东西假了。。

因为我们漏下了一些情况,再回头考虑我们设置的时候为必须满足 p 子节点的关键节点都和 p 连通,但是如果不连通,且除 p 子树之外的所有节点都非关键节点,那么此时我们这几条从 p 子树中关键节点到 p 的边无论是否保护都是合法的,但是我们却忽略了,所以此时要考虑维护一下这个东西。

这个东西我们可以考虑将状态改为 dp(p,0/1/2),分别表示考虑 p 所在子树,子树内没有关键点,或有关键点且要求子树外没有关键点,或有关键点且不要求子树外没有关键点。当然这个东西写起来要多考虑一些东西,所以我们也可以换个思路,直接尝试去补上漏下的。

我们实际上可以在 e-BCC 缩点之后再跑一遍 dfs,维护一下对应子树中的包括被缩掉的所有边的数量,设其为 sp,(或者给 树形DP 加个返回值记录一下好像也行,不过细节会更多)不失一般性,设根为 1,那么当我们维护完 dp(p,1) 的时候,我们算漏的方案数似乎就是:dp(p,1)×2s1sp,也就是子树内设置关键点,子树外不设置关键点,则子树外的所有边都是任意的。然后你会发现这个东西又假了。。

考虑发现如果 pfa 的边被连上了,那么这个东西已经被 dp(fa,1) 给计算过了,这样会重,所以我们钦定 pfa 的边不选择,即可做到不重不漏,这样最终此处的贡献就是 dp(p,1)×2s1sp1

然后注意对于根节点时,其不存在我们刚才说的漏下的那些方案,但需要加上一般的答案,也就是 dp(1,1)

至此,这道细节巨多的题就做完了。

Code

UPD

update-2022_11_29 初稿