首先不难看出一个暴力的 \(dp\) 解法,考虑令 \(dp_{i, j}\) 表示考虑完前 \(i\) 个矩形,第 \(i\) 个矩形左端点在 \(j\) 时所需要的最小花费。

不难有转移:

\[dp_{i, j} = \min\limits_{j - (r_{i - 1} \ - \ l_{i - 1} \ ) \le k \le j + (r_{i} - l_{i})}{dp_{i - 1, k}} + |j - l_i|
\]

继续考虑对上面这个 \(dp\) 进行优化,可以发现的是,这个 \(dp\) 本质上是在对之前的某个区域取 \(\min\) 然后再加上一个之和每个位置有关的绝对值函数。

看起来十分抽象,那么我们可以考虑把抽象问题具体化,将 \(dp_i\) 看作是一个关于 \(j\) 的函数,再来考虑一下转移。

从初始的 \(i = 1\) 开始考虑,不难发现 \(dp_1\) 就是 \(y = |j - l_1|\) 这样一个绝对值函数。

再来考虑 \(i = 2\) 的情况,可以发现前一步取 \(\min\) 本质上是将这个绝对值函数的左段向左平移了 \(r_i - l_i\),右段向右平移了 \(r_{i - 1} - l_{i - 1}\),中间用一段斜率为 \(0\) 的线段接起来。

再来考虑加入 \(|j - l_i|\) 这个绝对值函数,不难发现图像的变化需要分三种情况,但整体的变化方式都是确定的,即 :

  • \(l_i\) 左边的函数斜率整体 \(-1\) 右边的函数斜率整体 \(+1\),同时斜率变化的点的横坐标不变。

可以发现,这样变化后的图像一定还是一个下凸包。

那么就不难通过归纳证明每次转移的过程都是类似于 \(i = 2\) 的情况的。

同时,因为每一个函数 \(dp_i\) 的斜率最大最小值都不会超过 \(\pm |2i - 1|\),因此我们可以考虑直接维护这些斜率变化的拐点。

为了方便起见,如果在这个拐点斜率变化了 \(k\),我们就直接插 \(k\) 个这个点进去代表斜率变化了 \(k\) 个 \(1\)。

首先,因为左右两个函数的平移是不同的,因此我们要分开维护左右两边的断点。

并且,因为函数只是平移,因此我们只需要记录当前平移了多长的距离即可,下面着重来考虑加入一个绝对值函数的过程。

  • 当插入的绝对值函数零点在图像斜率为 \(0\) 的那段上时。

不难发现左边之前的拐点还是拐点,右边亦然。唯一变化的是左边右都会要在 \(l_i\) 处添加一个拐点。

  • 当插入的绝对值函数零点在图像斜率为 \(0\) 的那段左边时。

不难发现此时左边会在 \(l_i\) 处添加两个拐点,同时失去最靠右的拐点,右边会得到左边失去的哪个拐点。(注意这里的拐点实际上代表着斜率变化为 \(1\),这样就方便地处理掉左边做靠右的直线斜率不为 \(-1\) 的情况了)

因为需要取出最右边的端点,因此我们需要一个大根堆来维护左边的拐点。

  • 当插入的绝对值函数零点在图像斜率为 \(0\) 的那段右边时。

同理于上一种情况,用小根堆维护右边的拐点。

那么最终的答案是什么呢?

不难发现其实是最终 \(dp_n\) 斜率为 \(0\) 的那段函数对应的纵坐标。

但是我们并没有记录每一次的纵坐标,怎么办呢?

你会发现每次斜率为 \(0\) 的直线位置总是会向右或者向左变化,而这两次斜率为 \(0\) 的直线中会存在一个交点。

同时因为对于每一层而言,取斜率为 \(0\) 线段上的点总是最优的。

结合上面那条性质,每次选定一个斜率为 \(0\) 的线段做为这一层的 \(j\) 即可,然后计算答案只要计算往下一层斜率为 \(0\) 交点纵坐标的变化量即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 1e5 + 5;
int n, l, r, nL, nR, TL, TR, len, ans, lastlen;
priority_queue <int> L;
priority_queue <int, vector <int>, greater <int> > R;
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
signed main() {
n = read(), l = read(), r = read();
L.push(l), R.push(l), lastlen = r - l;
for (int i = 2; i <= n; ++i, lastlen = len) {
l = read(), r = read(), len = r - l, TL += len, TR += lastlen;
nL = L.top() - TL, nR = R.top() + TR;
if(l < nL) ans += nL - l, L.pop(), R.push(nL - TR), L.push(l + TL), L.push(l + TL);
else if(l > nR) ans += l - nR, R.pop(), L.push(nR + TL), R.push(l - TR), R.push(l - TR);
else L.push(l + TL), R.push(l - TR);
}
printf("%lld", ans);
return 0;
}

这种方法被称为 \(\rm set\) 维护函数拐点,经常用与维护一次分段函数的变化问题。

AT2347 [ARC070C] NarrowRectangles的更多相关文章

  1. [atARC070E]NarrowRectangles

    记$len_{i}=r_{i}-l_{i}$,即第$i$个区间的长度 用$f_{i,j}$表示前$i$个区间合法,第$i$个区间位于$[j,j+len_{i}]$的最小代价,暴力dp的时间复杂度为$o ...

  2. AtCoder 杂题训练

    前言: 因为要普及了,今年没一等就可以退役去学文化课了,所以暑假把历年noip普及组都刷了一遍,离noip还有50+天,想弄点强化训练什么的. 想了想,就这些天学文化课之余有空就把AtCoder之前那 ...

  3. AtCoder刷题记录

    构造题都是神仙题 /kk ARC066C Addition and Subtraction Hard 首先要发现两个性质: 加号右边不会有括号:显然,有括号也可以被删去,答案不变. \(op_i\)和 ...

  4. 【AtCoder】ARC070

    ARC070 C - Go Home 题目大意:一只袋鼠第i秒可以向左或向右跳i步或者不跳,问从0跳到x的最小时间 就是1,2,3,4...k总和超过x的最小的k,因为如果超过了x的那部分需要减掉的那 ...

随机推荐

  1. Windows 11实现直播,VLC超简单实现捕获、串流、播放

    上一篇文章说了搭建Nginx的rtmp服务.实现直播功能 期间发现一个更便捷的工具 VLC media play,官方下载:https://www.videolan.org 1.傻瓜式安装,略过 2. ...

  2. uniapp中拿到base64转blob对象,或base64转bytes字节数组,io操作写入字节流文件bytes

    1. uniAPP中拿到附件的base64如何操作,如word文件 /*** 实现思路:* 通过native.js的io操作创建文件,拿到平台绝对路径* 再通过原生类进行base64解码,拿到字节流b ...

  3. [高数]高数部分-Part II 导数与微分

    Part II 导数与微分 回到总目录 Part II 导数与微分 一元函数微分的定义 一元函数定义注意点 基本求导公式 基本求导方法 复合函数求导 隐函数求导 对数求导法 反函数求导 参数方程求导 ...

  4. PHP 的扩展类型及安装方式

    扩展类型 底层扩展(基于C语言): PECL 上层扩展(基于PHP 语言): PEAR Composer PECL # 查找扩展 $ pecl search extname # 安装扩展 $ pecl ...

  5. python 之 pip、pypdf2 安装与卸载

    pip是个啥? pip 是一个现代的,通用的 Python 包管理工具.提供了对 Python 包的查找.下载.安装.卸载的功能. 第一步:pip 下载:https://pypi.org/projec ...

  6. 曾经大量使用的Model1开发模式,虽不常用,但可以帮我们理解JSP

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6513394762370777604/ 1.<JSP页面实际上就是Servlet> 2.<JSP页 ...

  7. vue js格式化数字为金额格式

    /** * @description 格式化金额 * @param number:要格式化的数字 * @param decimals:保留几位小数 默认0位 * @param decPoint:小数点 ...

  8. 关于CKCsec安全研究院

    关于CKCsec安全研究院 CKCsec安全研究院所有文档开源于语雀,会源源不断更新. 部分内容 微信公众号 知识星球 使用需知 由于传播.利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均 ...

  9. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  10. java关于for循环的效率优化

    我们知道在实现一个功能的时候是可以使用不同的代码来实现的,那么相应的不同实现方法的性能肯定也是有差别的,所以我们在写一些对性能很敏感的模块的时候,对代码进行优化是很必要的,所以我们说一下for循环(w ...