[ARC070E] NarrowRectangles

news/2025/1/14 21:28:21/文章来源:https://www.cnblogs.com/YzaCsp/p/18671737

前言

模拟赛 \(\rm{T4}\) , 不会比较正常, 仅仅只是记录做法

然后就是还有每日一练

思路

首先是朴素的 \(\rm{dp}\)
\(f_{i, j}\) 表示考虑到第 \(i\) 行, 其中这一行的左端点位置为 \(j\) 的最优花费
容易写出转移

\[f_{i, j} \gets \min_{k \in [j - len_{i - 1}, j + len_i]} f_{i - 1, k} + |j - l_i| \]

考虑优化
注意到绝对值是「凸函数」, 你把 \(f_{i, j}\) 视做 \(n\) 个函数 \(f_i(x)\) , 容易递归证得 \(f_i(x)\) 也是「凸函数」

用函数的形式表示 \(f_{i - 1}\) , 然后考虑转移
pEitndf.png

你发现转移相当于在这个函数上做一个滑动窗口, 然后求最小, 具体的
pEitJLq.png

记中间那一段斜率为 \(0\) 的左右端点为 \(L, R\)

利用你的初中数学知识得到表达式

\[\begin{align*} f_i (x) \gets |x - l_i| + \begin{cases} f_{i - 1} (x + len_i) , \textrm{ case } x \in (-\infty, L - len_{i}) \\ f_{i - 1} (L) , \textrm{ case } x \in [L - len_i, R + len_{i - 1}] \\ f_{i - 1} (x - len_{i - 1}) , \textrm{ case } x \in (R + len_{i - 1}, \infty) \\ \end{cases} \end{align*} \]

你发现如果只考虑大括号, 就是一个对 \(L, R\) 的偏移, 使得中间斜率为 \(0\) 的部分拉长, 然后两边扩张

具体为什么 : 左加右减常数项, 上加下减自变量

考虑加上绝对值
首先不难证明, 绝对值函数由 \(k = -1, 1\) 的一次函数拼成, 可以看做对 \(x = l_i\) 左侧的 \(k \gets k - 1\) , 对 \(x = l_i\) 右侧的 \(k \gets k + 1\)

考虑其影响, 你发现对 \(l_i\) 两侧的斜率 \(\pm 1\) 并不好维护
你发现斜率 \(\pm 1\) , 如果 \(l_i\) 恰好在原来的端点上, 会保持一个优美的性质: 相邻两线段 \(k\) 值相差为 \(1\)
考虑维护每一个斜率对应的线段的左右端点, 你会发现 \(l_i\) 不在端点上时, 会出现相邻两线段 \(k\) 相差 \(2\) 的情况, 怎么办
大胆令 \(x = l_i\) 这个点的斜率为相邻两线段的 \(k\) 中间值, 于是满足了这个美丽性质

由上, 我们把 \(L\) 左侧以及 \(L\) 的线段端点 (上面的图中的红色点) 放到一块, 把 \(R\) 右侧以及 \(R\) 的线段端点放到一块, 一会解释为什么

那么我们现在大可以把 \(f_i \gets f_{i - 1}\) 分成两次操作

  • 处理斜率的变化, 会产生新的左右端点
  • 处理 \(L, R\) 的偏移

具体一点, 我们来模拟一些这样的过程

处理斜率的变化

对于 \(l_i < L\)

pEiarlQ.png

你可以看做把原来的 \(L\) , 也就是 左侧最小的线段端点 弹出 左侧线段端点 , 然后把它放进 右侧线段端点
还需要把 \(l_i\) 所处的位置看做一个新的端点放进左侧端点的集合中, 因为

大胆令 \(x = l_i\) 这个点的斜率为相邻两线段的 \(k\) 中间值, 于是满足了这个美丽性质

所以要放两个 \(l_i\) 进去, 表示左右端点

注意负数斜率 \(-1\), 在画图的时候表示为更陡

对于 \(l_i > R\)

跟上面的情况是类似的, 对称
绝对不是我懒

对于 \(L \leq l_i \leq R\)

pEia8QH.png
你发现 \(l_i\) 变成了左右的同时端点, 其他的不变

处理 \(L, R\) 的偏移

显然可以处理每次操作的偏移量
这里有一个小问题, 你无法同时更新两个部分中所有的端点位置, 怎么办
很巧妙的方法是, 你每次将 \(L, R\) 还原之后插入, 然后对两个部分维护偏移量, 即可动态维护 \(L, R\) 的位置

现在可以解释为什么

我们把 \(L\) 左侧以及 \(L\) 的线段端点放到一块, 把 \(R\) 右侧以及 \(R\) 的线段端点放到一块, 一会解释为什么
首先是这样可以快速求出 \(f_i\)\(L, R\) , 只需要对 \(L\) 维护大根堆, 对 \(R\) 维护小根堆即可


最后一个问题: 答案怎么求得

你发现最后的答案可以表示成 \(f_n (L \sim R)\) , 可惜不好维护
考虑每次操作的时候, 动态维护当前的 \(f_i (L), f_i(R)\)


具体怎么做?
首先需要发现偏移操作并不影响 \(y\)

对于上文中 \(l_i < L\) 的情况

我们可以发现这种情况下, 答案会变成 \(f_{i - 1} (L) + (L - l_i)\)

对于上文中 \(l_i > R\) 的情况

我们可以发现这种情况下, 答案会变成 \(f_{i - 1} (L) + (l_i - R)\)

对于上文中 \(L \leq l_i \leq R\) 的情况

我们可以发现这种情况下, 答案不变


动态维护即可


总结一下, 每次维护新的 \(f_i\) , 我们首先计算偏移量, 然后维护新的线段端点, 统计对答案的影响

总结

清新 \(\rm{dp}\) , 这种没有后效性的问题要多考虑 \(\rm{dp}\)

特殊性质 : 凸函数

对于特殊的操作, 比如本题中只会造成 \(k \pm 1\) 的情况, 考虑特殊维护
一般可以先找特殊性质, 然后推广到一般上

多个操作考虑分开考虑

对于这种处理 \(L_{\max}, R_{\min}\) 类问题, 堆处理是常见的, 一般分左右端点讨论

多画画图可以找到操作的性质, 需要画一些更一般的图

答案无法直接统计时, 考虑每次操作动态维护答案的变化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869263.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PDF Automation文档页面自动化工具

PDF Automation是我用VB6开发的一个PDF文档页面自动化工具。电脑必须安装了Adobe Acrobat才能使用该工具。软件的主要功能包括:文档的拆分 文档的合并 页面的删除 页面的移动 页面的插入等。 软件界面正中央的区域是文档列表,也就是多个PDF文档,最右侧是页面列表,显示当前所…

not_the_same_3dsctf_2016 1

打开ida能看到栈溢出,返回地址填到get_secret函数里面,可以看到get_secret函数是直接读取了flag的,现在就需要把它输出即可。 输出我们可以利用代码里面的printf,因为printf从缓冲区打印出东西需要满足条件,比如有换行符或缓冲区已满或程序正常退出。 这里我们用exit让程序…

JS-35 数组方法_reverse()

reverse方法用于颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组 var a =[a,b,c]; a.reverse()//["c","b","a"];

FastGPT及大模型API(Docker)私有化部署指南

本文提供了FastGPT及其相关大模型API的Docker私有化部署指南,旨在简化部署流程并降低设备配置要求。文章重点介绍了优化后的部署配置、推荐使用的部署容器以及部署步骤,确保用户能够在不影响FastGPT功能的前提下,以高效的资源利用实现快速部署。1. **部署优化**:本文首先指…

LCT

1 概述 首先我们需要知道一类问题,在这类问题中我们需要维护一个森林,支持加边和删边操作,然后要求维护树上的一些信息。这类问题称为动态树问题。 而 LCT,即 Link-Cut Tree,就是用于解决动态树问题的一种数据结构。 学习 LCT 之前需要对 Splay 这种平衡树有一定了解,当然…

git整体使用流程

一、场景说明本地有文件 想在github创建一个远程仓库 在本地修改,同时同步到远端二、流程设置用户名和邮箱目的:标识每次提交者的身份 设置全局用户名:git config --global user.name "Your Name" 设置全局邮箱:git config --global user.email "your.email…

【Linux性能】Linux 下利用 Valgrind 进行内存调试

一、概述 Valgrind 是一个开源的内存调试和性能分析工具,用于帮助开发者找出程序中的内存错误,如内存泄漏、使用未初始化的内存、非法内存访问等问题。它在 Linux 平台上广泛使用,并且支持下多种处理器架构。 二、Valgrind 的使用 2.1 基本格式 valgrind --tool=memcheck -–…

C#/.NET/.NET Core技术前沿周刊 | 第 21 期(2025年1.6-1.12)

前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。欢迎投稿、推荐或自荐优质文章、项目、学习资源等…

26. 文件操作

一、数据读写在 PySide6 中对文件和文件夹的进行操作时,主要使用 QFile 类、QFileInfo 类和 QDir 类。我们可以在终端中使用 pip 安装 pyside6 模块。 pip install pyside6在 PySide6 窗口程序对文件或者文件夹进行操作时,不强制要求必须使用 PySide6 中提供的 QFile、QDir 等…

MySQL基础函数使用

DQL中的函数 # 官方函数链接 https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format4.1 单行函数函数都是数据库提前给我们准备好的,所以我们可以直接调用,使用函数可以让指定的列计算出我们需要的数据 单行函数 : 指的是操作一行数据…

【模拟电子技术】06-双极晶体管的结构与放大原理

【模拟电子技术】06-双极晶体管的结构与放大原理图(b)中我们可以看到三个区的分类,发射区之所以为发射区是因为掺杂浓度高,才能发射电子出去。而集电区掺杂浓度低,就好比我们想让一个房间当作仓库,那么它的空间肯定要大,里面原本不能是放了很多东西。下图NPN晶体管中发射…