标签:har std using 最大 splay href min 队列 --
斜率优化dp
考虑一类\(dp\)方程
\(min\)改成\(max\)也是可以的
其中\(val\)中含有\(ij\)乘积这一项
例题:任务安排
转移方程
把式子拆开,把\(dp[j]\)放到左边,\(dp[i]\)放到右边作为截距中的一项
对于每一个确定的\(i\),截距都是\(dp[i]+C\),其中\(C\)只与\(i\)有关
所以我们要最小化截距,于是我们维护一个点集为\((sumf[i],dp[i])\)的下凸包
由于这道题斜率一定,所以我们相当于是用一条斜率为\(s+sumt[i]\)的直线去切这个凸包
所以我们找到\(k\le s+sumt[i]\)且\(k\)最大的点即可,这个\(k\)是表示这一个点和前一个点之间的斜率(具体可以画个图)
维护凸包,并且横坐标递增,斜率递增,直接上单调队列即可
#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar();
}
#define maxn 5005
int t[maxn], f[maxn], q[maxn], dp[maxn], n, s;
inline int dy(int x, int y) { return dp[y] - dp[x]; }
inline int dx(int x, int y) { return f[y] - f[x]; }
int main()
{
read(n), read(s);
for (int i = 1; i <= n; ++i) read(t[i]), read(f[i]), t[i] += t[i - 1], f[i] += f[i - 1];
for (int l = 1, r = 1, i = 1; i <= n; ++i)
{
while (l < r && dy(q[l], q[l + 1]) <= 1ll * (s + t[i]) * dx(q[l], q[l + 1])) ++l;
dp[i] = dp[q[l]] - (s + t[i]) * f[q[l]] + t[i] * f[i] + s * f[n];
while (l < r && 1ll * dx(q[r - 1], q[r]) * dy(q[r], i) < 1ll * dx(q[r], i) * dy(q[r - 1], q[r])) --r;
q[++r] = i;
}
printf("%d\n", dp[n]);
return 0;
}
以及如果两个都不单调,就要上平衡树/cdq,比如这个
标签:har std using 最大 splay href min 队列 --
原文地址:https://www.cnblogs.com/123789456ye/p/12642183.html