Submission #1288578

#TimeUsernameProblemLanguageResultExecution timeMemory
1288578harryleeeSplit the sequence (APIO14_sequence)C++20
71 / 100
230 ms196608 KiB
#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 timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...