Submission #566192

#TimeUsernameProblemLanguageResultExecution timeMemory
566192quickslothSplit the sequence (APIO14_sequence)C++17
71 / 100
424 ms82072 KiB
#include <iostream> using namespace std; #define maxn 100000 #define maxk 200 #define ll long long int best[maxn][maxk]; //arr is prefix sums int main() { ll dp[maxn], prv[maxn], arr[maxn]; //prv is not quite necessary int n, k; cin >> n >> k; k++; //array endgth n, split into k+1 intervals, each time points = product of sums of two sides //if decided how intervals will be picked: then how to arrange which to select? //answer for a set of intervals = sum ab where a, b are distinct in it //true by induction on set's size //= ((sum a)^2 - sum a^2)/2 where first sum is known (sum of array) and second is split up //divide up the array optimally to minimize sum (segment sum)^2? dp with prefix sums for (int i = 0; i < n; i++) { cin >> arr[i]; if (i) arr[i] += arr[i-1]; //1 interval dp[i] = arr[i]*arr[i]; best[i][0] = -1; //cut at -1 means this is final interval } int stack[maxn]; ll cut[maxn+1]; cut[0] = 0; //stack[0] is best from cut[0] to cut[1]-1, ... int end, start; for (int t = 1; t < k; t++) { //t+1 intervals to make 0..i-1; if t = 0 then just interval sum ^ 2 //else: dp[i] = min_x<i arr[i]^2 - 2*arr[x]*arr[i] + arr[x]^2 + prv[x] //with x >= t-1 (i >= t to make it well defined) //do all of dp[?] in O(n)? need to insert another x or query best x for given i //monotonic stack: record pair<int,ll>: best value of x for arr[i] <= that ll for (int i = 0; i < n; i++) prv[i] = dp[i]; end = 0; start = 0; for (int i = t; i < n; i++) { //x = i-1: insert it into the monotonic stack ll x = 0; bool special = false; while (start != end) { //see when it beats the last function, then truncate //definitely should work at some value of arr[i]: prv is increasing not too fast //just assume it ought to work //solve for smallest int x: //arr[stack[end-1]]*arr[stack[end-1]]+prv[stack[end-1]]-2*arr[stack[end-1]]*x > //arr[i-1]*arr[i-1]+prv[i-1]-2*arr[i-1]*x //or tmp2x > tmp1 or x = ceil of (tmp1+1)/tmp2 //just take floor and +1 if needed if (arr[i-1] == arr[stack[end-1]]) { //impossible to beat previous function, so done special = true; break; } ll tmp1 = arr[i-1]*arr[i-1]+prv[i-1]-arr[stack[end-1]]*arr[stack[end-1]]-prv[stack[end-1]], tmp2 = 2*arr[i-1]-2*arr[stack[end-1]]; x = (tmp1+1)/tmp2; if ((tmp1+1)%tmp2) x++; //if at some point it is optimal, it will continue to be optimal later if (x > cut[end-1]) { //previous one is sometimes optimal so cannot discard break; } end--; } if (!special) { stack[end] = i-1; cut[end] = x; end++; cut[end] = 9e18; } //the last curve is always optimal, but previous one is up to x-1 only //now find which curve is best for arr[i]: pop from front of the stack while (start != end) { if (cut[start+1] > arr[i]) break; start++; } best[i][t] = stack[start]; dp[i] = (arr[i]-arr[stack[start]])*(arr[i]-arr[stack[start]])+prv[stack[start]]; } } //now dp[n-1] is the answer cout << (arr[n-1]*arr[n-1]-dp[n-1])/2 << '\n'; int cur = n-1; while (k) { cur = best[cur][--k]; if (cur != -1) cout << cur+1 << ' '; } }
#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...