[luogu4072][bzoj4518][SDOI2016]征途
阿新 • • 發佈:2019-03-28
line 斜率 amp %d bits can long ems spa
題目分析
Pine開始了從S地到T地的征途。
從S地到T地的路可以劃分成n段,相鄰兩段路的分界點設有休息站。
Pine計劃用m天到達T地。除第m天外,每一天晚上Pine都必須在休息站過夜。所以,一段路必須在同一天中走完。
Pine希望每一天走的路長度盡可能相近,所以他希望每一天走的路的長度的方差盡可能小。
幫助Pine求出最小方差是多少。
分析
比較簡單的斜率優化。
\[f[i][j]=min(f[k][j-1]+m(sum[i]-sum[j])^3-s\times s_n(s_i-s_j))\]
答案就是\(f[n][m]+sn^2\)
化簡玩後滾動數組優化一下。
代碼
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define ll long long #define db double #define N 3005 using namespace std; int a[N]; ll sum[N], f[N], g[N], q[N]; int n, m; ll sqr(ll x) { return x * x; } ll X(int i) { return sum[i]; } ll Y(int i) { return g[i] + sqr(sum[i]); } db slope(int i, int j) { return (1.0 * Y(j) - 1.0 * Y(i)) / (1.0 * X(j) - 1.0 * X(i)); } ll calc(int l, int r) { return sqr(sum[r] - sum[l - 1]); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i], g[i] = sqr(sum[i]); for (int k = 1; k < m; k ++) { memset(f, inf, sizeof(f)); int h = 0, t = 0; q[0] = k; for (int i = k + 1; i <= n; i ++) { while (h < t && slope(q[h], q[h + 1]) < 2 * sum[i]) h ++; int j = q[h]; f[i] = min(f[i], g[j] + calc(j + 1, i)); while (h < t && slope(q[t - 1], q[t]) > slope(q[t], i)) t --; q[++ t] = i; } memcpy(g, f, sizeof(g)); } printf("%lld\n", f[n] * m - sum[n] * sum[n]); return 0; }
[luogu4072][bzoj4518][SDOI2016]征途