bzoj4518
http://www.lydsy.com/JudgeOnline/problem.php?id=4518
水了一发斜率优化 好久没写了 调了一个晚上
dp[i][j]:第i天走到了第j个休息站
dp[i][j] = min(dp[i-1][x] + (s[i]-s[x]-v)^2)v是平均数=s[n]/m
然后我们化简一下得到了一个式子 (h[j]-h[k])/(s[j]-s[k])/2<=s[i]是不优的(这里我好像把小于等于号推反了,这里是对的)那么我们就可以斜率优化了
然后写了很长时间
注意:1.队列是l<r 2.要赋初值
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3010; int n, m; ll v; ll s[N], h[N], dp[N][N]; int q[N]; double slope(int j, int k) { return ((double)h[j] - (double)h[k]) / ((double)s[j] - (double)s[k]) / 2.0; } void solve() { for(int i = 0; i <= n; ++i) dp[1][i] = (s[i] - v) * (s[i] - v); for(int i = 2; i <= m; ++i) { int l = 1, r = 0; q[++r] = 0; dp[i][0] = v * v + dp[i - 1][0]; for(int j = 0; j <= n; ++j) h[j] = dp[i - 1][j] + s[j] * s[j] + 2 * v * s[j]; for(int j = 1; j <= n; ++j) { while(l < r && slope(q[l], q[l + 1]) <= s[j]) ++l; dp[i][j] = min(dp[i - 1][q[l]] + (s[j] - s[q[l]] - v) * (s[j] - s[q[l]] - v), dp[i - 1][j] + v * v); while(l < r && slope(j, q[r]) <= slope(q[r - 1], q[r])) --r; q[++r] = j; } } printf("%lld\n", dp[m][n] / m); } int main() { freopen("menci_journey.in", "r", stdin); freopen("menci_journey.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { ll x; scanf("%lld", &x); s[i] = s[i - 1] + x * (ll)m; } v = s[n] / (ll)m; solve(); fclose(stdin); fclose(stdout); return 0; }