题目大意
记将 (i) 到 (j) 合并的代价为 $ (sum_{k = i}^j C_k + j - i - L) ^ 2$ 求总代价最小。
方便起见,全文的 (j) 的范围都是 (j < i)
解析
显然我们能有一种朴素的 (DP) , 记 (f[i]) 表示前 (i) 个最小的代价,(sum[i]) 表示 (C_i) 前缀和,我们有如下转移 $$f[i] = min{ f[j] + (sum[j] - sum[i] + j - i +1 - L) ^ 2 }$$
为了更加简洁的表达,我们记 (sum[j] + j) 为 (a[i]) 记 (1-L) 为 (l) 则有 $$f[i] = min{ f[j] + (a[i] - a[j] - l)^2 }$$
显然如果我们暴力进行转移的话,复杂度是 (O(n^2)) 的,下面我们利用 (坐标化) 的思想,通过 (斜率优化) 将复杂度降为 (O(nlogn))
对于我们要求的第 (i) 项,(a[i]) 和 (l) 都是定值,于是原式可以化为
移项可以得到$$f[i] - (a[i] - l)^2=min{-2 * a[i] * a[j] + (f[i] + a[j]^2 + 2 * a[j] * l)}$$
令z = (f[i] - (a[i] - l)^2), (k = 2 * a[i]), (x = a[j]), (y = (f[j] + a[j]^2 + 2 * a[j] * l)),
原式就变成了:
因为要求 (f[i]) 最小,那么 (z) 要最小;对于确定的 (j), (x, y)都是定值, 所以有
因此,我们可以将求解这个问题抽象成求解所有经过 (x_j, y_j) 的直线中,截距最小是多少。由于 (k) 给定,我们不难发现答案的最优选取是在下凸包上的。由于(a[i]) 单调,则 (k) 单调,我们可以通过一个队列维护下凸包,进而降低编程复杂度。