首先不难看出一个暴力的 \(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. Codeforces 919D:Substring(拓扑排序+DP)

    D. Substring time limit: per test3 seconds memory limit: per test256 megabytes inputstandard: input ...

  2. C++判断月份天数(判断闰年)

    题目描述 输入年份和月份,输出这一年的这一月有多少天.需要考虑闰年. 输入格式 无 输出格式 无 输入输出样例 输入 #1 输出 #1 1926 8 31 输入 #2 输出 #2 2000 2 29 ...

  3. Exploring Architectural Ingredients of Adversarially Robust Deep Neural Networks

    目录 概 主要内容 深度 宽度 代码 Huang H., Wang Y., Erfani S., Gu Q., Bailey J. and Ma X. Exploring architectural ...

  4. SpringBoot集成Log4j2框架

    1.说明 本文详细介绍Spring Boot集成Log4j2框架的方法, 基于已经创建好的Spring Boot工程, 由于Spring Boot默认使用的是Logback框架, 需要先排除掉Logb ...

  5. CSS基础-7 盒子模型大小

    在盒子模型当中,有些元素是影响盒子大小的. 首先border就会影响盒子的大小. 其次padding也会影响盒子的大小. 例子: .one { width:100px; height:100px; b ...

  6. 03.python封装与解构

    封装与结构 基本概念 t1 = 1, 2 print(type(t1)) # 什么类型 t2 = (1, 2) print(type(t2)) Python等式右侧出现逗号分隔的多值的时候,就会将这几 ...

  7. centos7-collabora-office(在线文档编辑)

    1.wget https://www.collaboraoffice.com/repos/CollaboraOnline/CODE-centos7/repodata/repomd.xml.key &a ...

  8. tomcat 服务器的几个重要监听 方法 与 使用

    1. 总结一下tomcat 服务器里的三种监听 ServletContextListener HttpSessionListener ServletRequestListener 这是我要做的三个自定 ...

  9. Spark-2.0.2源码编译

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6813925210731840013/ Spark官网下载地址: http://spark.apache.org/d ...

  10. vue爬坑之路(webpack 配置篇)

    在vue cli下 1.npm run dev 打开浏览器在config的index.js中修改autoOpenBrowser为true 关闭sourcemap productionSourceMap ...