CSES: Array Division
Abridged problem statement
Given an array containing positive integers, divide it into subarrays minimizing the maximum subarray sum.
Again, let’s fix the maximum subarray sum. Let be if there exists a valid division of into subarrays with each one of them having a sum , and otherwise.
Notice that a division that is valid for will also be valid for . Thus, in this case, will look like this:
To check whether a division for exists, we’d iterate over the elements of the array. Ideally, we want to use the least number of subarrays as possible, since if we end up using , we can always just split up one of the existing ones into two different subarrays and this will only ever improve our answer. Notice that this means that we want each subarray to be as big as possible.
To begin with, if there exists an element in our array which is larger than , the answer is immediately .
If this is not the case, we can keep expanding our current subarray until its sum exceeds . At the end, we count how many ‘splits’ we’ve made, which will correspond to one less than the number of subarrays.
The lower bound on the answer is , and the upper bound is .
Code
#include <bits/stdc++.h>
typedef long long ll;
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
ll n, k;
std::cin >> n >> k;
std::vector<ll> a(n);
for (auto &i : a) {
std::cin >> i;
}
ll max_e = *std::max_element(a.begin(), a.end());
ll sum = std::accumulate(a.begin(), a.end(), 0LL);
auto f = [&](ll x) {
if (max_e > x) {
return false;
}
ll splits_made = 0;
for (ll i = 0, current_sum = 0; i < n; ++i) {
current_sum += a[i];
if (current_sum > x) {
splits_made++, current_sum = a[i];
}
}
return splits_made <= k - 1;
};
ll l = 0, r = sum;
ll ans = sum;
while (l <= r) {
ll m = std::midpoint(l, r);
if (f(m)) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
std::cout << ans << '\n';
}