#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
int n, k, trace[maxn + 1][201];
long long bestPos = 0, res = LLONG_MIN/4, pre[maxn + 1];
const long long NEG = LLONG_MIN/4;
struct Line {
long long m; // slope (a)
long long b; // intercept (b)
int id;
Line(long long _m=0, long long _b=0, int _id=0): m(_m), b(_b), id(_id) {}
};
// check if l2 is unnecessary between l1 and l3
inline bool bad(const Line &l1, const Line &l2, const Line &l3){
// (b3 - b1) / (m1 - m3) <= (b2 - b1) / (m1 - m2)
// Cross multiply to avoid floating point.
long long left = (long long)(l3.b - l1.b) * (long long)(l1.m - l2.m);
long long right = (long long)(l2.b - l1.b) * (long long)(l1.m - l3.m);
return left <= right;
}
struct CHT {
vector<Line> hull;
int ptr = 0; // pointer for queries with non-decreasing x
void clear(){ hull.clear(); ptr = 0; }
// slopes must be added in non-decreasing order
void add(Line L){
// if last slope == new slope, keep the one with bigger intercept
while(!hull.empty() && hull.back().m == L.m){
if (hull.back().b >= L.b) return; // new line dominated
else hull.pop_back(); // remove dominated last line
}
while(hull.size() >= 2 && bad(hull[hull.size()-2], hull.back(), L))
hull.pop_back();
hull.push_back(L);
if (ptr >= (int)hull.size()) ptr = (int)hull.size() - 1;
}
// query maximum at x; x must be non-decreasing between queries
pair<long long,int> query(long long x){
if (hull.empty()) return {NEG, 0};
while(ptr + 1 < (int)hull.size()){
long long v1 = (long long)hull[ptr].m * x + (long long)hull[ptr].b;
long long v2 = (long long)hull[ptr+1].m * x + (long long)hull[ptr+1].b;
if (v2 >= v1) ++ptr;
else break;
}
long long val = (long long)((long long)hull[ptr].m * x + (long long)hull[ptr].b);
return {val, hull[ptr].id};
}
};
// number of levels max k is up to 200 -> allocate 201
CHT lc[201];
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
if (!(cin >> n >> k)) return 0;
for (int i = 1; i <= n; ++i){
cin >> pre[i];
pre[i] += pre[i - 1];
}
// init
for (int j = 0; j <= k; ++j) lc[j].clear();
lc[0].add(Line(0, 0, 0));
for (int i = 0; i <= n; ++i){
for (int j = 0; j <= k; ++j) trace[i][j] = 0;
}
for (int i = 1; i <= n; ++i){
int mxj = min(i, k);
for (int j = mxj; j >= 1; --j){
auto g = lc[j-1].query(pre[i] - pre[n]);
if (g.first == NEG){
trace[i][j] = 0;
continue;
}
long long dp = g.first + pre[i] * (pre[n] - pre[i]);
if (j < k) lc[j].add(Line(pre[i], dp, i));
if (j == k && i < n && dp > res){
bestPos = i;
res = dp;
}
trace[i][j] = g.second;
}
}
cout << res << '\n';
vector<int> cuts;
while (bestPos != 0 && k > 0) {
cuts.push_back((int)bestPos);
bestPos = trace[bestPos][k];
--k;
}
reverse(cuts.begin(), cuts.end());
for (int i = 0; i < (int)cuts.size(); ++i){
if (i) cout << ' ';
cout << cuts[i];
}
cout << '\n';
return 0;
}
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |