2023.1.30 upd:因为忘了 slope trick 想再学学,重新看了一下这个题解,发现是完全的误人子弟。只是一个很低的角度的理解方法,还是学习zxy的教程
感觉十分厉害的题,记录一下(
有个很显然的 的 dp,设 为 变为 ,考虑原序列 的最小代价。
显然有:
结论1: 关于 的点相邻两个连起来是一个下凸壳。
证明:
,是一个绝对值函数,顶点在 。
考虑 会发生怎样的变化。
分类讨论一下,具体可以看这里的证明,我认为写得非常地好,无需多补充,不过请务必看懂有关下凸壳的证明,后面的做法会涉及到加入 对下凸壳线段的影响。
下凸壳的斜率肯定是递增的。先钦定线段的斜率是不断 的,如果中间出现了断层的现象就当作这个断的地方有长度为 的线段,这些线段的斜率补充了中间断层的地方。
再设 为 的斜率为 的那一条线段的左端点,也是斜率为 的那一条线段的右端点。
我们需要明确一点,最终答案是 ,换句话说,我们只关心 的纵坐标,不关心 具体是几,因为问题只要求输出最小的代价。
现在可以完全不管斜率 的线段了,它们怎么变和求答案没有关系。
考虑维护这些斜率 的线段,设计一个可重元素的由大到小的优先队列(或者说大根堆),其元素为线段的右端点,一个右端点可以重复多次,其线段的斜率为其需要完全 pop 出的次数的相反数。
举个栗子,大根堆为 ,那么右端点为 的线段的斜率为 ,因为弹出全部的 需要把一个 ,两个 全部弹出。
现在惊奇地发现,这个优先队列恰好对上了我们前面钦定的斜率不断 递增"的"暴论"。
关于要用到的结论上面给出的链接已经证明,我现在重新叙述一遍。
-
线段单降且在 左侧,斜率 (其斜率的数值减去 );
-
线段单降且在 右侧,斜率 ;
-
线段不单降且在 左侧,斜率变为 ;
-
线段不单降且在 右侧,斜率变为 ;
考虑从 到 ,一个 会对答案造成怎样的影响。
设答案为 ,也就是考虑 增加时 如何改变。
Case1:
这个时候 前面的线段斜率都 了,而 又是 取到最小值时的 ,又在 前面,所以可以从 转移而来。答案变为 处的取值即为 , 不变。
由于前面的线段斜率都会 ,要维护堆的意义,就把 push 进堆中,这样堆中所有元素其 pop 完的次数都 ,则斜率就 。
Case2:
首先考虑答案改变成什么样子,注意到新的决策点 即为图中红点和 之间的斜率变为了 ,所以 。例如图中,这个时候每部分的线段的斜率由图中黑色的变成红色的,中间有一段 中间断开了,少了 ,换句话说,由于我们 push 进去了 ,还想要维护堆的意义,就要把 弹出,再把 压进去,使其拥有斜率为 的段。
我们要维护堆能够以 递增实际上是让每次 的时候保证加进去 后 作为右端点代表的线段斜率变为了 ,保证它一定是需要弹出的点。所以多 push 进去是对的。
图中为一个栗子,值得注意的是两条线段之间的长度可能为 ,但这不影响答案。
综上所述,我们得到了一个很简洁的代码来完成这个过程。
时间复杂度
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T &read(T &r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = (r << 3) + (r << 1) + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 500010;
int n, a;
std::priority_queue<int>q;
long long ans;
signed main() {
read(n);
for(int i = 1; i <= n; ++i) {
read(a); q.push(a);
if(a < q.top()) {
ans += q.top() - a;
q.pop();
q.push(a);
}
}
printf("%lld\n", ans);
return 0;
}
感谢slyz的两位学长的指点以及 Mr_Wu 的题解。
笔者才疏学浅,如有错误欢迎指出,如有疑惑也欢迎提出。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?