0%

LOJ3059 「HNOI2019」序列

参考资料

Sol

部分分:m=0

考虑一个更加一般的形式:已知 wi,Ai0,要求确定 Bi,使得 BiBi+1wi(AiBi)2 最小。

定义一个点集 U 的均值为:让 jUwj(Ajk)2 取到最小值的 k。对于这道题,k=jUwjAjjUwj(通过求导可得)

引理 1

能达到最优解的 {Bi} 是唯一的。

证明:将 (A1,A2,An)(B1,B2,Bn) 看作两个 n 维向量,权值函数可以看作两个点之间的距离。由于不等式组 BiBi+1 的解空间是一个凸集,所以到 A 的距离最短的 B 是唯一的。

引理 2

如果 Ai>Ai+1,那么最优解中一定有 Bi=Bi+1

证明:参考 IOI2018 集训队论文《浅谈保序回归问题》

引理 2 启发我们可以考虑这样的一个过程:每一次找到一个满足 Ai>Ai+1i,然后将 ii+1 合并。具体地,应该把 (wi,Ai),(wi+1,Ai+1) 替换为 (wi+wi+1,wiAi+wi+1Ai+1wi+wi+1),这样前后的权函数只相差一个常数,直接在合并的时候把这个常数加入答案即可。合并到无法合并的时候,直接令每个 Bi 都取 Ai,这就是最优方案。最终的答案就是在合并的过程中产生的那些常数的和。

由引理 1 可知,无论以任何顺序合并,最终得到的 {Bi} 都是相同的,所以合并过程完成以后得到的那些同值的段(下文称为等值段)也一定是相同的。

正解

把询问离线下来依次处理。对于询问 (x,y),先处理好只考虑 [1,x1][x+1,n] 时,等值段的划分情况(可以用从左到右和从右到左的单调栈分别维护)。

最终的划分方案一定是:保留 [1,x1] 的等值段划分的一个前缀,保留 [x+1,n] 的等值段划分的一个后缀,剩下的部分和 x 合并为一段。设这个前缀包含了 [1,x1] 的前 L0 个等值段,这个后缀包含了 [x+1,n] 的后 R0 个等值段。设 L0,R0 之间(不含 L0,R0)的元素合并起来后的权值(也就是它们的平均值)为 v(L0,R0)。设 [1,x1] 中从左到右第 x 段的 Ailv(x),设 [x+1,n] 中从右到左第 x 段的 Airv(x)

考虑如何求出 L0,R0。我们对 L0,R0 的要求是:

  • lv(L0)<v(L0,R0)<rv(R0)
  • L0,R0 之间的元素确实能合并成一段(即合并过程中不存在把 Ai<Ai+1 的两个元素合并了的情况)

考虑这样一个算法:从大到小枚举 R0,然后求出最大的 L0,使得 lv(L0)<v(L0,R0);如果 v(L0,R0)<v(R0) 就退出,把此时的 L0,R0 作为答案,否则继续枚举 R0

  • 对于某个固定的 R0 来说
    • 考虑某个比求出的 L0 更小的 L0v(L0,R0) 一定合并了不能合并的段(即满足 Ai<Ai+1 的两个段)
    • 考虑某个比求出的 L0 更大的 L0v(L0,R0) 一定还能和左边的段合并,所以不可能和 R0 一起作为最终的等值段
  • 故而,对于固定的 R0 来说,最大的满足 lv(L0)<v(L0,R0)L0唯一可能使 (L0,R0) 合法L0

假设 r 为算法结束时的 R0:任意一个大于 rR0 显然不可能成为最终的等值段的右端点(因为还可以和右边的段合并);而任意一个小于 rR0v(L0,R0) 一定合并了不能合并的段。

所以,算法结束时求出来的 L0,R0 就是我们想求的答案。

算法的优化:

  • 在已知 R0 的情况下求最大的满足 lv(L0)<v(L0,R0)L0
    • 可以证明,如果 L0 满足条件,那么 L01 也满足条件
      • 由于 lv(L0)<v(L0,R0),又因为 lv(L01)<lv(L0),所以 lv(L01)<v(L0,R0),那么 lv(L01) 一定小于 lv(L0),v(L0,R0) 中的元素的平均值(也就是 v(L01,R0)),所以 L01 一定也满足条件
    • 所以可以直接二分 L0
  • 求最大的 R0,使得满足 lv(L0)<v(L0,R0) 的最大的 L0 也满足 v(L0,R0)<rv(R0)
    • 一个重要的观察是,对于某个固定的 R0,满足 lv(L0)<v(L0,R0) 的最大的 L0,就是使 v(L0,R0) 取到最大值的 L0
    • 可以证明,如果 R0 满足条件,那么R01 也满足条件
      • R0 求出的 L0LR01 求出的 LL,那么 v(L,R0)v(L,R0)<rv(R0)<rv(R01)v(L,R0)rv(R0) 都小于 rv(R01),所以 v(L,R01) 小于 rv(R01)
    • 所以可以直接二分 R0

总时间复杂度为 O(nlog2n)

Code

my submission on loj.ac