现场得分 (28 + 100 + 26 = 154)。
(A)
首先 , 考虑动态规划。
设 (f_{i,j}) 表示前 (i) 段墙壁 , 交给第 (j) 个及之前的承包商粉刷 , 最多匹配的长度。
注意到 (f_{i}) 之和 (f_{i - 1}) 有关 , 因此可以用滚动数组来优化空间复杂度。
这样就求出了第 ([i - m + 1 , i]) 这段区间的墙壁是否可以被某个承包商粉刷。
将所有可以的位置排序 , 然后贪心地尽可能往后放即可。
时间复杂度 : (O(N))
代码 : https://loj.ac/submission/922889
(B)
首先考虑一个 (O(NMlogN)) 的做法。
二分答案 (mid) , 保留图中权值不超过 (mid) 的边 , 如果图中有环或度数超过 (2) 的点 , 那么就符合要求。
这是因为可以让一辆车在一个节点处停留 , 等另一辆车到达目的地后再继续开。
这样可以得到 (37) 分。
接着 , 考虑克鲁斯卡尔重构树 , 对于重构树上每个节点记一个权值 , 代表的是这个联通块最早符合要求是什么时候。
回答询问时 , 先求出 (u) 和 (v) 的最近公共祖先 。 再倍增至第一个权值非空的节点 , 即可。
时间复杂度 : (O((N + M)logN))。
代码在考场上。
(C)
首先找出这棵树的重心。 这需要花费 (2M) 次操作。
注意到每个点的度数不超过 (3)。
如果重心的度数为 (2) , 由重心的性质 , 两棵子树大小差不超过 (1) , 每次取不同于上次所选的那棵子树中 , 剩下的深度最大的节点来构造出一种合法方案。
如果度数为 (3) , 延续刚才的思路 , 每次取不同于上次所选的两棵子树中剩余深度最大的节点。
这样做必然有一时刻 , 某两棵子树的大小和等于另一棵子树的大小。 其正确性在于 :
记函数 (V = 2 cdot max{size} - sum{size}) , 由重心的性质得到函数 (V) 的初值小于 (0)。
这个函数在每次操作后的变化量为 (1) , 因此一定存在某一时刻满足 (V = 0)。
因此 , 在这个时刻到来时 , 将两棵较小的子树合并 , 用度数等于 (2) 的方法处理即可。
总操作数 (4M)。时间复杂度 : (O(NlogN))。
代码 : https://loj.ac/submission/926697