【题目链接】
【思路要点】
- 凸优化 + 决策单调性优化 d p dp dp 。
- 时间复杂度 O ( N L o g V L o g N ) O(NLogVLogN) O(NLogVLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct info {ll cost; int cnt; }; info operator + (info a, ll b) {return (info) {a.cost + b, a.cnt + 1}; } bool operator < (info a, info b) { if (a.cost == b.cost) return a.cnt < b.cnt; else return a.cost < b.cost; } bool operator <= (info a, info b) { if (a.cost == b.cost) return a.cnt <= b.cnt; else return a.cost < b.cost; } bool operator > (info a, info b) { if (a.cost == b.cost) return a.cnt > b.cnt; else return a.cost < b.cost; } bool operator >= (info a, info b) { if (a.cost == b.cost) return a.cnt >= b.cnt; else return a.cost < b.cost; } info Max[MAXN], Min[MAXN]; int n, k, a[MAXN]; ll Extra, s[MAXN]; ll cost(int l, int r) {return (s[r] - s[l]) * (s[r] - s[l]); } info TransMax(int x, int y) {return Max[x] + (cost(x, y) + Extra); } info TransMin(int x, int y) {return Min[x] + (cost(x, y) + Extra); } void check(ll extra) { int LMax = 1, RMax = 1, LMin = 1, RMin = 1; Extra = extra; static pair <int, pair <int, int> > SMax[MAXN], SMin[MAXN]; SMax[1] = make_pair(0, make_pair(1, n)); SMin[1] = make_pair(0, make_pair(1, n)); for (int i = 1; i <= n; i++) { Max[i] = TransMax(SMax[LMax].first, i); Min[i] = TransMin(SMin[LMin].first, i); if (++SMax[LMax].second.first > SMax[LMax].second.second) LMax++; if (++SMin[LMin].second.first > SMin[LMin].second.second) LMin++; while (LMax <= RMax && TransMax(i, SMax[RMax].second.first) >= TransMax(SMax[RMax].first, SMax[RMax].second.first)) RMax--; if (LMax > RMax) SMax[++RMax] = make_pair(i, make_pair(i + 1, n)); else if (TransMax(i, n) > TransMax(SMax[RMax].first, n)) { int l = SMax[RMax].second.first, r = SMax[RMax].second.second + 1; while (l < r) { int mid = (l + r) / 2; if (TransMax(i, mid) > TransMax(SMax[RMax].first, mid)) r = mid; else l = mid + 1; } SMax[RMax].second.second = l - 1; SMax[++RMax] = make_pair(i, make_pair(l, n)); } while (LMin <= RMin && TransMin(i, SMin[RMin].second.first) <= TransMin(SMin[RMin].first, SMin[RMin].second.first)) RMin--; if (LMin > RMin) SMin[++RMin] = make_pair(i, make_pair(i + 1, n)); else if (TransMin(i, n) < TransMin(SMin[RMin].first, n)) { int l = SMin[RMin].second.first, r = SMin[RMin].second.second + 1; while (l < r) { int mid = (l + r) / 2; if (TransMin(i, mid) < TransMin(SMin[RMin].first, mid)) r = mid; else l = mid + 1; } SMin[RMin].second.second = l - 1; SMin[++RMin] = make_pair(i, make_pair(l, n)); } } } int main() { read(n), read(k), k++; for (int i = 1; i <= n; i++) read(a[i]), s[i] = s[i - 1] + a[i]; ll l = 0, r = 1e18; while (true) { ll mid = (l + r) / 2; check(mid); if (Min[n].cnt <= k && Max[n].cnt >= k) { printf("%lld\n", (s[n] * s[n] - Min[n].cost + mid * k) / 2); return 0; } if (Min[n].cnt < k) r = mid - 1; else l = mid + 1; } return 0; }