斜率优化
斜率优化
斜率优化在判断线段左右关系时应善用叉积.
// b 在 a 的逆时针为正,夹角为 a 转到 b 的有向角度(sin)
double cross(Vector a, Vector b) {
return a.x * b.y - a.y * b.x;
}
通常会把题目化简成求最小截距,然后求最小截距具有一定的单调性故可以维护凸包.
同时,也可以看成是若干个一次函数求固定某个横坐标时的最小交点,可以用李超线段树来维护.
摆渡车
来源:洛谷P5017
斜率优化做法:
#include <bits/stdc++.h>
#define N 6000009
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll dp[N], sum[N];
int num[N], q[N], head, tail, n, m;
ll cross(int a, int b, int c, int d) {
// (a, b) and (c, d)
return 1ll * a * d - b * c;
}
ll Y(int x) {
return sum[x] + dp[x];
}
ll X(int x) {
return num[x];
}
int main() {
// setIO("input");
scanf("%d%d", &n, &m);
int mx = 0;
for(int i = 1; i <= n ; ++ i) {
int x;
scanf("%d", &x);
num[x] ++ , sum[x] += 1ll * x;
mx = max(mx, x);
}
for(int i = 1; i <= mx + m; ++ i) {
sum[i] += sum[i - 1];
num[i] += num[i - 1];
}
head = 1, tail = 0;
for(int i = 0; i <= mx + m ; ++ i) {
// 当前的斜率要求.
if(i - m >= 0) {
// i - m 进来.
while(head < tail&&cross(X(q[tail])-X(i-m),Y(q[tail])-Y(i-m),X(q[tail-1])-X(i-m),Y(q[tail-1])-Y(i-m))>=0)
-- tail;
q[++ tail] = i - m;
}
while(head < tail && Y(q[head + 1])-Y(q[head])<1ll*i*(X(q[head + 1])-X(q[head])))
++ head;
if(i < m) {
dp[i]=1ll*num[i]*i-sum[i];
}
else {
dp[i]=1ll*num[i]*i-sum[i]+Y(q[head])-1ll*i*num[q[head]];
}
}
ll ans = 1000000000000ll;
for(int i = mx; i <= mx + m ; ++ i)
ans = min(ans, dp[i]);
printf("%lld", ans);
return 0;
}

浙公网安备 33010602011771号