这道题想了很久,终于想出来了,非常抽象。
经过一番无脑推导,我们发现u里面有没有军营,是否与根连通,u的子树有没有军营,……都对方案数有影响,然后我就一直修修改改,事实证明,当发现越来越多题目条件中被忽略的细节时,一定不要嫌麻烦,要从头开始设置状态。
首先我们发现,子树中有没有军营对于与子树相连的边选不选是有影响的,也就是说对状态多了一个限制:有没有军营。
然后就会想:子树如果没有军营,儿子边可选可不选;有军营,就一定要选……等等,一定要选吗?如果只选了一个儿子,而且u没有军营的话,其实是可以不选的,然后我尝试加加减减乘乘除除。然后你会发现,子树有军营,但是没和v连在一起,就算儿子边选了,u和军营还是不连通,……根本算不出来……于是整理一下思路。
我们注意到,dp难以转移的关键在于子树中军营与u的连通性(只选一个儿子,可以不连通,选了多个儿子,又一定要连通)。
-
如果子树中恰好只有一个儿子v,T(v)中有军营,那么它与u是否连通是无所谓的。
-
如果子树中有超过两个儿子v,T(v)中都有军营,那么它们就一定要与u连通(也就一定要与v连通)。
考虑T(v),此时多了一个限制条件,即“T(v)中的军营与v是否连通”。
f(u,0)表示没有军营的方案数。
f(u,1)表示有军营,并且军营与u连通的方案数。
f(u,2)表示有军营,并且军营与u不连通的方案数。
由于每次分类是不重不漏的,所以答案就是有军营的方案,也就是有军营、连通或有军营、不连通的和,即f(u,1)+f(u,2)。
考虑转移(记u到儿子的边为儿子边):
f(u,0):因为T(u)都没有军营,(其实可以用公式算,但是我懒),所以每个儿子都一定不选,而且儿子边选也可以,不选也可以,所以就是每个2*f(v,0)乘起来,最后乘上u自身的方案(没有军营,方案等于点的方案乘上边的方案,也就是\(1\times 2^{cnte(u)}\))。
f(u,1):先考虑单个儿子v,如果T(v)里面有军营(注意,不是v里面有军营,这也是之前推错的原因),那么它一定要和u连通,也就是边一定选:1*f(v,1);如果T(v)没有军营,那么边可选可不选,也就是2f(v,0),注意到这里是分类,所以用加法原理,每个子树的方案就是 \(f(v, 1) + 2f(v, 0)\)。
自然地想到,每个儿子用乘法原理乘起来就行了,最后再乘上u的方案即可。
这里重点来了:每次写完转移之后,都要考虑这样转移是否充要。上述写法就是说:所有儿子,要么选并且连通,要么不选的方案数。而这样的集合里面有没有军营的方案数,而状态定义中是要求一定要有军营的,所以要减去多出来的方案。
我们会发现,全部不选,也就是u不选点,儿子也不选点,那么也就是T(u)没有军营,那不就是f(u,0)么?
所以减去f(u,0)就行了。
f(u,2):同样,考虑单个儿子v,……
然后你就会发现方案数统计多了,这时候把所有方案画出来,一一与题设比对,找出不合法的方案,并将其剔除。
于是我们发现,如果军营不与u连通,那么只能有一个子树有军营。(不然两个军营之间没有保护的边,不符合题意)。
所以我们枚举这个有军营的儿子,其它儿子都没有军营,儿子边自然是可选可不选。因为这个有军营的儿子与u不相连,考虑儿子边的选法:选,则v和u相连了,军营不能和v连通,所以是f(v,2);不选,则v和u不相连,那么军营和v连不连通就无所谓了,所以是f(v,2)+f(v,1)。合起来就是2f(v,2)+f(v,1)。其它儿子都不能选,那么用一个累乘和逆元搞一下就行了。
上述选法会统计恰好一个子树有军营,且与u不连通的方案数,符合状态设计。
然后就拿下啦!
总结一下:
- 推导的时候,肯定会逐渐发现一些没有注意到的题目细节要求,当细节越来越多,状态会越来越乱,此时要重新定义状态。
- 列出所有发现的要求,列出来,抽象概括出若干个能够符合所有要求的根本要求,比如本题的根连通性和是否有军营。
- 然后根据每一个要求,依次分类讨论,其实本来是要有4类的,但是因为没有军营就不需要考虑连通性了(都没有点哪来连通性问题),所以本题只有3个状态。
- 推出式子之后记得返回去检查这样统计出来的方案数是否充要。
- 树形DP,可以先考虑每一个儿子,然后推出一个必要条件的方案数(每一个儿子都必须这样),然后再剔除不合法的方案(其实几乎所有情况都是状态定义中有要求至少XXX,但是求出来的情况包括了全部都没有的情况)。