[斜率优化]洛谷 P3628 特别行动队 题解
比较模板的一道题(? 没调就直接过了
首先看式子
\[dp_i = dp_j + a\times (sum_i - sum_j) ^ 2 + b \times (sum_i - sum_j) + c
\]
不难拆分,我们可以得到
\[a \times sum_j ^ 2- b \times sum_j + dp_j = 2a \times sum_i \times sum_j + dp_i - b \times sum_i - c
\]
直接代入一次函数 \(y = kx + b\) 即可
然后就是单调队列维护上凸壳,这个跟下凸壳是一模一样的,改一下单调队列就行
然后就没了
#include <bits/stdc++.h>
#define N 1000007
#define int long long
using namespace std;
int h , t , n , a , b , c , sum[N] , q[N] , dp[N];
inline int P(int x) {
return x * x;
}
inline int x(int i) {
return sum[i];
}
inline int y(int i) {
return a * P(sum[i]) - b * sum[i] + dp[i];
}
inline double slope(int i , int j) {
return (y(i) - y(j)) * 1.0 / (x(i) - x(j));
}
signed main() {
ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
cin >> n >> a >> b >> c;
for(register int i = 1; i <= n; ++i) {
cin >> sum[i]; sum[i] += sum[i - 1];
}
h = 1, t = 0;
for(register int i = 1; i <= n; ++i) {
while(h < t && slope(i - 1 , q[t]) >= slope(q[t - 1] , q[t])) {
--t;
}
q[++t] = i - 1;
while(h < t && slope(q[h] , q[h + 1]) >= 2 * a * sum[i]) {
++h;
}
int target = q[h];
dp[i] = dp[target] + P(sum[i] - sum[target]) * a + (sum[i] - sum[target]) * b + c;
}
cout << dp[n];
return 0;
}