Maximize the Minimum Powered City

hard binary search greedy sliding window

Problem

Each city i has stations[i] power stations. A station at city i powers every city j with |i − j| ≤ r. A city's power is the total stations covering it. You may build k more stations anywhere (multiple allowed per city). Return the largest possible value of the minimum city power.

Inputstations = [1,2,4,5,0], r = 1, k = 2
Output5
Build both extra stations at city 1 → [1,4,4,5,0]. Powers become [5,9,13,9,5]; the minimum is 5, which cannot be beaten.

def maxPower(stations, r, k):
    n = len(stations)
    power = [0] * n                      # base power of each city
    cur = sum(stations[:min(r + 1, n)])  # window [0, r] for city 0
    for i in range(n):
        if i > 0:
            if i + r < n:    cur += stations[i + r]    # slide right edge in
            if i - r - 1 >= 0: cur -= stations[i - r - 1]  # slide left edge out
        power[i] = cur

    def feasible(target):
        extra = [0] * n                  # difference array of built stations
        running = 0                      # extra coverage reaching city i
        used = 0
        for i in range(n):
            running += extra[i]
            p = power[i] + running
            if p < target:               # city i is too weak
                need = target - p
                used += need
                if used > k:             # ran out of budget
                    return False
                running += need          # cover city i now
                drop = i + 2 * r + 1     # this batch stops covering here
                if drop < n: extra[drop] -= need
        return True

    lo, hi = min(power), min(power) + k  # answer lies in this range
    while lo < hi:
        mid = (lo + hi + 1) // 2
        if feasible(mid): lo = mid       # mid works, aim higher
        else:             hi = mid - 1   # mid fails, aim lower
    return lo
function maxPower(stations, r, k) {
  const n = stations.length;
  const power = new Array(n).fill(0);          // base power per city
  let cur = 0;
  for (let i = 0; i <= Math.min(r, n - 1); i++) cur += stations[i];
  for (let i = 0; i < n; i++) {
    if (i > 0) {
      if (i + r < n) cur += stations[i + r];   // slide right edge in
      if (i - r - 1 >= 0) cur -= stations[i - r - 1]; // slide left edge out
    }
    power[i] = cur;
  }

  function feasible(target) {
    const extra = new Array(n).fill(0);        // difference array
    let running = 0, used = 0;
    for (let i = 0; i < n; i++) {
      running += extra[i];
      const p = power[i] + running;
      if (p < target) {                         // city i too weak
        const need = target - p;
        used += need;
        if (used > k) return false;             // out of budget
        running += need;                        // cover city i now
        const drop = i + 2 * r + 1;             // batch stops covering here
        if (drop < n) extra[drop] -= need;
      }
    }
    return true;
  }

  let lo = Math.min(...power), hi = lo + k;     // search range (BigInt-safe in real use)
  while (lo < hi) {
    const mid = lo + Math.ceil((hi - lo) / 2);
    if (feasible(mid)) lo = mid;                // mid works, aim higher
    else hi = mid - 1;                          // mid fails, aim lower
  }
  return lo;
}
long maxPower(int[] stations, int r, int k) {
    int n = stations.length;
    long[] power = new long[n];                  // base power per city
    long cur = 0;
    for (int i = 0; i <= Math.min(r, n - 1); i++) cur += stations[i];
    for (int i = 0; i < n; i++) {
        if (i > 0) {
            if (i + r < n) cur += stations[i + r];        // slide right in
            if (i - r - 1 >= 0) cur -= stations[i - r - 1]; // slide left out
        }
        power[i] = cur;
    }
    long lo = Long.MAX_VALUE;
    for (long p : power) lo = Math.min(lo, p);
    long hi = lo + k;                            // answer in [lo, hi]
    while (lo < lo + (hi - lo + 1) / 2 && lo < hi) {
        long mid = lo + (hi - lo + 1) / 2;
        if (feasible(power, r, k, mid)) lo = mid; // mid works, aim higher
        else hi = mid - 1;                        // mid fails, aim lower
    }
    return lo;
}

boolean feasible(long[] power, int r, long k, long target) {
    int n = power.length;
    long[] extra = new long[n];                  // difference array
    long running = 0, used = 0;
    for (int i = 0; i < n; i++) {
        running += extra[i];
        long p = power[i] + running;
        if (p < target) {                         // city i too weak
            long need = target - p;
            used += need;
            if (used > k) return false;           // out of budget
            running += need;                      // cover city i now
            int drop = i + 2 * r + 1;             // batch stops here
            if (drop < n) extra[drop] -= need;
        }
    }
    return true;
}
long long maxPower(vector<int>& stations, int r, int k) {
    int n = stations.size();
    vector<long long> power(n, 0);                // base power per city
    long long cur = 0;
    for (int i = 0; i <= min(r, n - 1); i++) cur += stations[i];
    for (int i = 0; i < n; i++) {
        if (i > 0) {
            if (i + r < n) cur += stations[i + r];          // slide right in
            if (i - r - 1 >= 0) cur -= stations[i - r - 1]; // slide left out
        }
        power[i] = cur;
    }
    auto feasible = [&](long long target) -> bool {
        vector<long long> extra(n, 0);            // difference array
        long long running = 0, used = 0;
        for (int i = 0; i < n; i++) {
            running += extra[i];
            long long p = power[i] + running;
            if (p < target) {                     // city i too weak
                long long need = target - p;
                used += need;
                if (used > k) return false;       // out of budget
                running += need;                  // cover city i now
                int drop = i + 2 * r + 1;         // batch stops here
                if (drop < n) extra[drop] -= need;
            }
        }
        return true;
    };
    long long lo = *min_element(power.begin(), power.end());
    long long hi = lo + k;                        // answer in [lo, hi]
    while (lo < hi) {
        long long mid = lo + (hi - lo + 1) / 2;
        if (feasible(mid)) lo = mid;              // mid works, aim higher
        else hi = mid - 1;                        // mid fails, aim lower
    }
    return lo;
}
Time: O(n · log k) Space: O(n)