P8499
首先,显然需要树哈希。哈希方法见 OIwiki。
设 \(f_i\) 表示 \(i\) 子树的哈希值,那么我们如何判断 \(G\) 能否通过删去不超过 \(k\) 个点变成 \(H\)?
考虑 \(solve(i,j,delta)\) 表示我们需要判断 \(G\) 的 \(i\) 子树是否能通过删去不超过 \(delta\) 个点变成 \(H\) 的 \(j\) 子树。
那么我们执行 \(solve(i,j,delta)\) 时,考虑枚举 \(i,j\) 的每一个儿子,并将这些儿子中子树形态相同的能匹配就匹配上,然后扔掉(可以通过预处理,对儿子的子树哈希值排序,然后直接双指针)。
可以发现这样贪心扔掉尽可能多的对一定会是最优解之一。证明显然。
然后考虑剩下的不同对。
直接对 \(i\) 的未匹配儿子枚举全排列,挨个判断一下按这个排列能否匹配 \(j\) 的未匹配儿子即可。
加一些剪枝优化即可通过。
具体地,当 \(i\) 的儿子个数小于 \(j\) 的儿子个数,枚举全排列时如果任意一对匹配满足 \(size_{a_i} < size_{b_j}\) 就直接不考虑这个序列,计算 \(\sum size_{a_i}-size_{b_j}\) 如果中途大于 \(delta\) 了就直接不合法。
复杂度比较玄学,但是容易发现这个算法的复杂度接近 \(O(n\times k!)\)。
P8290
考虑枚举最小值 \(x\),设 \(f_{u,x,0/1}\) 表示当前考虑 \(u\) 到某个子树内的一条链,最小值钦定是 \(x\),是否已经有最小值出现的方案数,再设 \(g_{u,x,0/1}\) 表示和,那么转移是容易的。
然后对于枚举一棵新子树的时候,我们在转移的同时也要考虑合并 \(u\) 到前面子树和 \(u\) 到这棵子树的链的并。这个也是简单的。
发现直接这样算,复杂度 \(O(nV)\)。
但是可以发现,如果 \(x\) 不是 \(l_i,r_i,l_i-k,r_i-k\) 类似的这些值,那么 \(x\) 在变化的过程中,答案值实际上是一个多项式。
于是对于这 \(O(n)\) 段选 \(n\) 个数出来 \(dp\) 然后直接插值即可。
标签:子树,匹配,枚举,哈希,delta,杂题,size From: https://www.cnblogs.com/infinities/p/17254466.html