学习把反复相邻消除变成前缀规范形相等,以及用 Lawler 逆序调度检验树上种植顺序。
前置:栈、哈希、二分答案、拓扑排序、等差数列。
一题在字符串上反复消除,另一题在树上选择种植时刻,表面上没有共性。但它们都需要丢掉完整过程,只保留会影响未来的边界:前者保留简化后的栈顶状态,后者把生长累积转成每个节点的最晚完成期限。
cc -> empty 可看成每个字符都是自身逆元。维护规范栈。压入时用哈希表把 (state,char) 映射到唯一节点,消除时回父状态。设前缀状态为 $Si$。子串 $(l..r)$ 的归约结果对应 $S{l-1}^{-1}S_r$,为空当且仅当两状态相同。于是统计相等前缀状态对。
每字符一次压/弹和哈希,期望 $O(n)$,空间 $O(n)$。
state = empty_stack; frequency[state] = 1
for character c:
if top(state) == c: state = parent(state)
else: state = intern(parent_state=state, top=c)
answer += frequency[state]
frequency[state] += 1
max(b_i+x*c_i,1),求所有树达到目标高度的最少总天数,$n\le10^5$。[1,D] 二分。二分 D。计算每点从种植日 t 到 D 的增长和;$b_i\ge 1$,$c_i$ 为任意整数(可正可负)。当 $c_i\ge 0$ 时高 $h(t) = b_i + (D-t)\cdot c_i$;当 $c_i<0$ 时先按等差递减,降到 1 后保持每日 1。若第 1 天都不足则不可行,否则二分最大 t 得 deadline。
检验调度时以未安排孩子数为度,把所有原树叶按 deadline 放入大根堆。从时间 n 倒到 1,每次取截止期最大叶;若其 deadline 小于当前时间失败,移除后父亲成为叶则入堆。
截止期定义与高度条件充要。Lawler 交换:任一可行逆序安排的最后任务必为当前极大元(叶);若它不是可选叶中截止期最大的,可把最大截止期叶换到该位置,它没有未安排后继且更晚截止,不破坏可行性。归纳得到贪心检验充要。外层二分因此返回最小完成日。
复杂度 $O(n\log D\cdot(\log n+\log D))=O(n\log^2 D+n\log n\log D)$;其中每个 $D$ 为每点二分 deadline,范围 $D\le10^9$。
feasible(D):
for each vertex i:
deadline[i] = latest planting day whose growth through D reaches a[i]
heap = all current tree leaves keyed by deadline
for time from n down to 1:
u = pop largest deadline
if deadline[u] < time: return false
remove u; if parent becomes leaf, push parent
return true
answer = first feasible D by binary search
《消消乐》对每个左端点重新扫描右端,栈中存字符与当前连续次数;只在栈空时统计合法段,避免把中间短暂消除误当终态。《种树》的外层答案判定要用 64/128 位计算生长和;内层 Lawler 逆序调度必须每次取当前可作为最后任务的节点,不是正序贪心。
消消乐把局部重写变成群规范形;种树把非线性增长变成截止期,再调用经典调度结构。两题都经历了两次模型转换。
消消乐与 $O(n^2)$ 子串判定对拍;种树对 n≤8 枚举所有拓扑序,对拍固定 D 的贪心可行性。