题意
思考
写的第一道斜率优化…感觉这个板题还蛮简单的
首先按普通思路,我们令 (dp[i]),为前 (i) 个物品的最小价值,那么可以很容易列出方程:
[dp[i] = min{ dp[j]+(sum[i]-sum[j]+i-j-1-L)^2 }
]
这是一个 (O(n^2))的 (dp),我们考虑如何优化它:
令 (s[x] = sum[x] + x, L=L+1),则
[dp[i] = dp[j]+(sum[i]-sum[j]+i-j-1-L)^2 \
= dp[j] + (s[i] - s[j] - L) ^ 2 \
= dp[j] + s[i]^2 + (s[j]+L)^2 - 2*s[i]*(s[j]+L)]
等式整理为:
[dp[i] + 2 * s[i] * (s[j] + L) = dp[j] + s[i]^2 + (s[j] + L) ^ 2
]
在这个式子里面,我们把 (dp[j] + s[i]^2 + (s[j] + L)) 看作因变量, (s[j]+L)看作自变量,(dp[i]) 看作 (y) 轴截距,(2*s[i])(已知量)看作直线斜率,那么我们就是要找到一个决策点 (j) 使得截距最小,根据 (k=2*s[i]) 我们可以发现这个斜率是单调递增的,那么我们维护的是一个下凸包,不多赘述。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double D;
const int N = 50050;
ll f[N], s[N], sum[N], n, L;
ll q[N], h, t;
D X(ll i){ return (D)s[i] + (D)L; }
D Y(ll i){ return (D)f[i] + (D)X(i) * (D)X(i); }
D slope(ll i, ll j){ return ( Y(i) - Y(j) ) / ( X(i) - X(j) ); }
int main(){
cin >> n >> L; L ++;
for(ll i=1; i<=n; i++) cin >> sum[i], sum[i] += sum[i-1], s[i] = sum[i] + i;
h = 1, t = 1;
for(ll i=1; i<=n; i++){
while(h < t && slope(q[h], q[h+1]) <= 2 * s[i]) h ++;
f[i] = f[q[h]] + (s[i] - s[q[h]] - L) * (s[i] - s[q[h]] - L);
while(h < t && slope(q[t], q[t-1]) >= slope(q[t], i)) t --;
q[++t] = i;
}
cout << f[n];
return 0;
}
总结
斜率优化中某些无关量可以在计算斜率的时候消去,所以不用管。
注意当前不变量和变量之间的关系。
注意变量类型。