4 道题全部只会暴力。还不如直接发下来当练习做呢,省得在场上罚坐三小时浪费时间。
简略题解
A – 神灵庙
观察发现:
- 当树的形态确定时,我们总是将权值更大的节点安插到深度更小的叶子上。可以将 a 降序排序后逐层填写。
- 一个节点只可能有 0 个或者 2 个儿子。如果只有 1 个儿子,显然可将该节点删除而整棵子树全部向上平移。
设 f(d,i,c1,c2) 表示“现在位于第 d 层(此处“层”指的是节点实际深度)。已经填写好了 a1,a2,⋯,ai,且第 d 层共 c1 个空置(非叶子)节点,第 d−1 层有 c2 个此类节点”。那么两层的每一空置节点,均会有一个第 d+1 层的儿子。枚举“下一层要填写 k 个元素”,有转移
f(d+1,i+k,c1+c2−k,c1)←f(d,i,c1,c2)+(j=i+1∑i+kaj)(d+1)
考虑转化贡献:我们并行计算每个尚未填写的权值的总和。假如我们在第 d 层仍未填写 ai+1,⋯,an,则总和必加上 ∑j=i+1naj。只要在 1∼d 层填写了 a1,⋯,ai,则不在下方层级计算它们的贡献。于是状态与 d 无关。存在相似转移:
f(i+k,c1+c2−k,c1)←f(i,c1,c2)+j=i+1∑naj
直接计算是 O(n4) 的,不能接受。但我们发现,记 f(i,c1,c2) 能够转移到的所有合法状态为 f(i’,c1’,c2’)。则必然有 c2’=c1,i’+c1’=i+c1+c2。又由于有 i 递增的转移顺序,故而我们可对于所有 i+c1=s 且 c2 恒定的状态保存一决策集合 g(s,c2),每次转移时以常数时间调用并更新即可。
时间复杂度 O(n3)。
B – 辉针城
如果两子串相等,则其二者对应位置的字符相等。暴力用并查集合并相等字符,就得到 O(α(n)∑len) 的算法。
考虑优化这个过程。若我们知晓有若干等长的(长度记为 l)的,下标从 x1,x2,⋯,xk 开始的子串两两相等,则设定分界点 p<l,有长度为 p 的从 x1,⋯,xk 开始的子串亦相等,且长度为 l−p 的从 x1+p,⋯,xk+p 开始的子串亦相等。我们将这一关系转化称为“下放”。
那么,我们将 lw 规定为 2w,pw 规定为 2w−1,w 取遍所有自然数。则题目中的每一个询问,都可以被拆分为 O(log2len) 个长度为 lw 的子串,这些子串对应位置两两相等。考虑开设 O(log2n) 个并查集,按照 w 递减的顺序依次遍历每个拆分后的子串,合并相同者并“下放”。实现时,在第 w 层,对于每个元素 x,记其相等类的代表元素为 y,我们将 x,y 和 x+2w−1,y+2w−1 在第 w−1 层合并即可。
时间复杂度 O(α(n)nlogn),空间可以优化到线性。
C – 绀珠传
这种转化是我抓破头都猜不出来的那种。
考虑最优方案中是否存在“交为空”的分组。若存在,则我们将所有交为空的组合并,最后一定剩余 K−1 个非空组;那么,我们贪心选择前 K−1 长的线段最优——显然有两条线段的交的长度不超过两线段长度最小值。
如果不存在“交为空”的分组,则将这些线段分为两类:S,T。若不存在线段 [l,r] 的子集 [p,q],p≥l,q≤r,则将 [l,r] 归入 S;否则归入 T。由此,S 中则不存在两条线段的左端点相同,且按左端点递增排序时,右端点一定亦严格递增。
考虑每一组的线段来源。如果该组存在属于 S 的线段,则我们称该组为“基准组”。若钦定有 ∣S∣≥k≥K−∣T∣ 组基准组,则最优方案一定具有以下特征:
- 每一基准组采用的 S 中线段,必然是 S 按左(右)关键字排序后连续的一段;
- 若有 T 中线段 [l,r] 欲加入基准组,则由 S,T 的定义,必然存在至少一条线段 [p,q]∈S,满足 [p,q]⊆[l,r]。加入 [p,q] 所在的基准组,不会继续减少该基准组的实际贡献;
- 在此前提下,我们希望尽可能多地选择若干条 T 中线段,将每条线段单独分为一组。事实上,我们选择的恰为 T 中前 K−k 长的线段。
当确定了 S 的分段方案后,第二条特征将保证其贡献不减少;而第三条特征最大化了 T 中线段能够做出的贡献。
于是问题转化成:将 S 依序分成 k 段,问每一段的交的长度之和最大为何。记有 ∣S∣=n,S={[l1,r1],⋯,[ln,rn]}。若一种方案在 t1,t2,⋯,tk (tk=n) 处分段,则总长为
(r1−lt1)+(rt1+1−lt2)+⋯+(rtk−1+1−ln)
它只有和 ti 线性相关的项,且互相独立。于是我们令权值 wi=−li+ri+1,权值和即为 r1−ln+∑i=1k−1wti。则贪心选择即可。
时间复杂度 O(nlogn)。
D – 天空璋
我们可以轻松借助差分思想和线段树区间加操作,维护每个节点 x=1,⋯,n 往 y=1,2,⋯,n 连边的代价。
假设现在经过了若干次迭代,正进行下一次迭代的连边。我们欲求取“从每个节点 x 向不属于目前连通块的点的最小边”。则在线段树上维护区间最小值,每一节点均保存两个来自不同连通块的点的连边代价,总有一个和 x 所在连通块不同。并查集维护连通情况即可。
时间复杂度 O(nlog2n)。