Plozia
2021-09-29 21:40:24
宣传博客
Slope Trick,是一种优化 DP 的方式,这个方式目前好像并不盛行,但是以前好像还挺流行的(?),网上讲 Slope Trick 的博客好像也不多(?)。
现在笔者得知的能够使用 Slope Trick 的题目并不多,这里主要讲 CF 的一道题,好像是已知的 Slope Trick 最早出现的时间(2016 年)(?)。
注意 Slope Trick 不是斜率优化 dp,这两个是不同的算法。
先放例题:CF713C Sonya and Problem Wihtout a Legend。
简要题意:给定
当然我们需要加强到
首先发现严格递增这个东西我们有一个套路的方式就是令
然后我们有一个简略的 DP 方程:
设
这个 DP 方程还是比较简单的吧~
这样,我们就能够在
此时 Slope Trick 就可以派上用场了。
首先我们需要知道 Slope Trick 能够优化什么问题:通常情况下,Slope Trick 能够解决的是一类凸函数问题。
啥意思呢?
比如说这道题的 DP 方程,我们首先转变一下式子:记
那么式子就是
然后仔细研究这个函数,我们会发现这个函数有下凸性质,画出来大概是这个样子:
需要注意的是,
我们记
然后我们重新看一下这个方程:
我们发现这个式子很有意思:我们只需要快速维护
具体怎么维护呢?
其实对于这种分段函数且各函数都是一次函数的情况下,有一种快速的方法维护最小值:维护所有分段点以及最右端一次函数即可。
比如说还是上图,可以发现我们只需要维护下图的红点和红线即可:
特别需要注意的是如果两个相邻段的斜率之差大于 1,那么这个关键点是要存两遍的。
那么现在我们来讨论如何通过所有已知的
有几个关键点:
根据上面的第四点,我们只需要维护所有左边的函数斜率小于 0 的关键点即可,也就是下面这些蓝色的点:
然后我们讨论一下
这个情况下你会发现,我们在函数叠加的时候,所有
从贪心的角度来理解,此时此刻你没必要将
至于如果后面的
于是我们只需要将
这个时候我们发现我们需要将
然后我们发现对于所有
此时我们发现在
最后将
有人可能会问:会不会存在在一个同样的值
这个情况吗……emm……确实是存在的,但是我们需要知道这道题的一个显然结论:
据此,实际上我们会发现将
↑上述问题其实也是我在学习的时候遇到的一个问题。
现在讨论完了两种情况,我们发现实际上我们只需要维护一个优先队列就可以完成快速维护关键点的工作。
而快速维护关键点实质上就是快速维护
那么最后答案当然就是
实际操作的时候我们不需要另外开一个 f[]
来存下所有的 ans
算贡献就好,因为我们的全部过程只需要利用到
代码如下:
/*
========= Plozia =========
Author:Plozia
Problem:CF713C Sonya and Problem Wihtout a Legend
Date:2021/9/22
========= Plozia =========
*/
#include <bits/stdc++.h>
using std::priority_queue;
typedef long long LL;
const int MAXN = 3000 + 5;
int n, a[MAXN];
LL ans = 0;
priority_queue <LL> q;
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum * 10) + (ch ^ 48);
return sum * fh;
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir < sec) ? fir : sec; }
int main()
{
n = Read();
for (int i = 1; i <= n; ++i) a[i] = Read() - i;
for (int i = 1; i <= n; ++i)
{
q.push(a[i]);
if (q.top() > a[i])
{
ans += q.top() - a[i];
q.pop(); q.push(a[i]);
}
}
printf("%lld\n", ans);
return 0;
}
Slope Trick 通常解决的是这样一类问题:
推荐练习题:P3642 [APIO2016]烟火表演。