[斜率优化]洛谷 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;
}
posted @ 2025-03-28 21:15  「癔症」  阅读(6)  评论(0)    收藏  举报