容易想到对每个点计算其作为重心的贡献。
设 fi,j,gi,j 分别表示 i 的子树内,包含 i 的大小为 j 的保证或不保证以 i 为重心的连通块的个数。
树形背包计算。
然而要明确计算出贡献,还需要知道往上的连通块方案数。
这可能需要换根 DP,复杂度将达到 O(nk2)。
实际上,可以将贡献放在连通块的顶端计算贡献。设 hi,j 表示 i 的子树内,所有包含 i 的大小为 j 的连通块的重心贡献和。
转移时应当结合 f。
有一个问题,这个东西的复杂度为何是 O(nk)?
这里贴一个 @mrsrz 教我的证明:
设所有未合并至父亲的背包大小的多重集为 S,设其势能函数为 Φ(S)=12∑x∈S(3xk−x2)
则初始时势能为 Φ(S0)=13(3nk−n),最终 Φ(Sn−1)=k2。
考虑一次合并大小为 a,b 的两个背包的摊还代价: ˆci=ci+Φ(Si)−Φ(Si−1)=ab+12(3min(a+b,k)k−min(a+b,k)2−3ak+a2−3bk+b2)=12(a+b+min(a+b,k))(a+b−min(a+b,k)−3k)≤0
于是总代价为 n−1∑i=1ci=Φ(S0)−Φ(Sn−1)+n−1∑i=1ˆci≤Φ(S0)−Φ(Sn−1)=O(nk)
代码:
1 |
|