Topics

Given an array of N integers, find a subarray with at most K odd numbers and the total sum is maximum but not more than D. If no such subarray exists print “IMPOSSIBLE”. Note that the array can contain -ve numbers as well.

Idea

This problem combines sliding window with variable window size (snake framework) with multiset STL. The key challenges are:

  1. Maintaining window validity (⇐ K odd numbers)
  2. Finding maximum subarray sum ⇐ D within valid windows

Warning

If a subarray from index L to R has number of distinct odd elements at most K, then all subarrays from index X to R (L < X) will also have number of distinct odd elements at most K. Note that the sum of the subarray won’t follow a similar rule since negative elements are also present in the array.

To efficiently calculate subarray sums, we use prefix sums. Window: [tail...head]. Find largest X in [tail...head] where prefs[X] - prefs[tail] <= D => prefs[X] <= prefs[tail] + D. If we use multiset to maintain sorted prefix sums of valid windows, then we can find largest prefix sum ⇐ (prefs[tail] + D) using upper_bound().

Time Complexity: due to sliding window and multisetops (takes )
Space Complexity: due to prefix array and multiset storage

Code

bool check(int val, int odd_count, int k) {
  return odd_count + (abs(val) % 2 == 1) <= k;
}
 
void solve() {
  int n, k;
  ll d;
  cin >> n >> k >> d;
  vector<int> arr(n);
  vector<int> prefs(n + 1);
  for (int i = 0; i < n; ++i) {
    cin >> arr[i];
    prefs[i + 1] = prefs[i] + arr[i];
  }
 
  ll ans = LONG_MIN;
  int tail = 0, head = -1;
  ll odd_count = 0;
  multiset<ll> seen;
 
  while (tail < n) {
    while (head < n - 1 and check(arr[head + 1], odd_count, k)) {
      head++;
      odd_count += (abs(arr[head]) % 2 == 1);
      seen.insert(prefs[head + 1]);
    }
 
    if (head - tail + 1 != 0){
        // for current tail, find the "valid" index
      ll val = d + prefs[tail];
      auto it = seen.upper_bound(val);
      if (it != seen.begin()) {
        it--;
        ll rpref = *it;
        ans = max(ans, rpref - prefs[tail]);
      }
    }
 
    // if window is valid
    if (tail <= head) {
      // undo effect of tail
      odd_count -= (abs(arr[tail]) % 2 == 1);
      seen.erase(seen.find(prefs[tail + 1]));
    }
 
    tail++;
    head = max(head, tail - 1);
  }
 
  if (ans == LONG_MIN)
    cout << "IMPOSSIBLE" << endl;
  else
    cout << ans << endl;
}

One might wonder why we can’t simply expand the window with both conditions directly, like:

while (head < n - 1 && check(arr[head + 1], odd_count, k) && (prefs[head + 2] - prefs[tail] <= d)) {
    head++;
    odd_count += (abs(arr[head]) % 2 == 1);
}

The reason is that this approach would be suboptimal for this specific problem. When we expand the window until sum > d, you only find the longest valid subarray starting at each tail. However, shorter subarrays within that window might have larger sums (while still being ⇐ d), since we are also dealing with -ve numbers.