Skip to main content
Back to problems
#3806
Hard Algorithms

Maximum bitwise and after increment operations

Array Greedy Bit Manipulation Sorting
31.3% acceptance
Mar 16, 2026
75
3
You are given an integer array nums and two integers k and m. You may perform at most k operations. In one operation, you may choose any index i and increase nums[i] by 1. Return an integer denoting the maximum possible bitwise AND of any subset of size m after performing up to k operations optimally.

Solution

Rust
Time O(n log n)
Space O(1)
LeetCode
solution.rs
impl Solution {
  pub fn maximum_and(nums: Vec<i32>, k: i32, m: i32) -> i32 {
    let n = nums.len();
    let m = m as usize;
    let k = k as i64;

    // Greedy bit-by-bit from highest to lowest.
    // Try to set bit b in the answer. If we can find m elements that can all
    // have bits [current_answer | bit_b] set with total cost <= k, keep that bit.

    // To check if a target value (with certain bits set) is achievable:
    // For each element, compute the cost to make it have all target bits set.
    // The cost to make nums[i] have all bits in `target` set:
    // We need nums[i]' >= some value that has all target bits set.
    // The minimum value with all target bits set that is >= nums[i]:
    // If nums[i] already has all target bits set, cost is 0.
    // Otherwise, we need to increment nums[i] to the next value that has all target bits.

    // For a given target (a mask), the cost for element x:
    // Find the smallest y >= x such that y & target == target.
    // Cost = y - x.

    // To find smallest y >= x with y & target == target:
    // Start with y = target. If y >= x, done.
    // Otherwise, we need to find the next value above x that has all target bits set.

    let cost_to_reach = |x: i64, target: i64| -> i64 {
      if x & target == target {
        return 0;
      }
      // Find smallest y >= x such that y & target == target
      // We process bits from high to low.
      // y must have all bits of target set, and y >= x.
      // Start with y = target. If y >= x, return y - x.
      if target >= x {
        return target - x;
      }
      // target < x but target has bits that x doesn't have.
      // We need to find the smallest y >= x with (y & target) == target.
      //
      // Strategy: look at bits from high to low.
      // For each bit position in target that is set, y must have it set.
      // For bit positions not in target, y can have any value.
      // We want the smallest such y >= x.
      //
      // This is like: find smallest y >= x where y OR target == y (i.e., target is subset of y's bits)
      // Equivalently, y = target | free_bits, minimize y subject to y >= x.

      // Simple approach: iterate from highest bit down
      // Let's just compute it directly.
      // We need all bits of target set in y. The free bits (not in target) can be anything.
      // So y = target | z where z can use any bits not in target (and also target bits are already set).
      // Actually y can have any bits set as long as target's bits are all set.
      // So y = target | extra, where extra is any non-negative integer.
      // We want smallest y = target | extra >= x.
      // Since target | extra >= target, and target < x, we need extra to supply the difference.

      // Actually, the simplest correct approach:
      // y must have all target bits set. Let free_mask = !target (bits we can freely set).
      // We want to find the smallest y >= x with y & target == target.
      // y = target | (y & free_mask). Let f = y & free_mask. Then y = target | f.
      // We need target | f >= x. Since target bits are fixed, we need to choose f
      // (using only bits in free_mask) to minimize target | f subject to target | f >= x.

      // Hmm, this is getting complicated. Let me use a different approach.
      // Just find the next value >= x with all target bits set.

      // Go bit by bit from MSB to LSB:
      let mut y = x;
      // Set all target bits in y. If a target bit is not set in y, we need to set it,
      // which might cause carries.
      // Process from lowest bit to highest to handle carries.

      // Alternative simpler approach:
      // The values with all target bits set form an arithmetic-like sequence.
      // Actually they don't form an arithmetic sequence in general.

      // Let's try: set all target bits in x. If any target bit was 0 in x, setting it
      // increases x. But we also need to clear bits below to minimize.
      //
      // Correct algorithm:
      // For each bit in target from low to high that is NOT set in current y, set it.
      // But this may create a value less than x if we also need to clear higher bits.
      //
      // Actually let me just use a simple formula:
      // missing = target & !x  (bits in target not in x)
      // If missing == 0, cost is 0 (handled above).
      // Otherwise, find the highest missing bit, say bit b.
      // Set bit b in x, clear all bits below b in x, then set all target bits.
      // This gives a value >= x with all target bits set.

      // Let me think again more carefully...
      // We want smallest y >= x, y & target == target.
      //
      // Approach: greedily build y from MSB to LSB.
      // We track whether y is already > x in the prefix (then we can set remaining bits minimally)
      // or y == x in the prefix (then we're constrained).

      // This is essentially a digit-DP but we can do it greedily.

      // Simple and correct: just add the missing bits one at a time from lowest.
      // When we set a missing bit, it might already be satisfied due to carry from addition.

      // Actually, the simplest correct O(30) approach:
      // Compute y = x, then for each bit in target not set in y (from low to high),
      // round y up to the next multiple that has that bit set.
      // But this is tricky with interactions.

      // Let me just do: try y = (x | target). If y >= x and y & target == target, done.
      // x | target always has target bits set, and x | target >= x. So y = x | target works!

      // Wait... x | target >= x always, and (x | target) & target == target always.
      // So the answer is just (x | target) - x = (x | target) - x.
      // But is x | target the SMALLEST such y? Not necessarily.
      // For example, x = 0b101, target = 0b010. x | target = 0b111 = 7.
      // But y = 0b010 = 2 < 5 = x, so that doesn't work. y = 0b110 = 6 > 5 and has bit 1 set.
      // Cost would be 6 - 5 = 1. x | target = 7 - 5 = 2. So x | target is not optimal.

      // Hmm, so we need a better approach. Let me think...
      // For x = 5 = 0b101, target = 0b010:
      // We need y >= 5 with bit 1 set. Candidates: 6(110), 10(1010), 14(1110)...
      // Smallest is 6. Cost = 1.
      // x | target = 7. Cost = 2. Not optimal.

      // OK so x | target is an upper bound but not always optimal.
      // The correct approach: find smallest y >= x with (y & target) == target.

      // Greedy from MSB: we have 30 bits. Let's say bits 29..0.
      // At each bit position, we decide the bit of y.
      // If the bit is required by target, it must be 1.
      // Otherwise, we try to match x's bit (to stay equal), or if we're already above, set 0.

      // If at some point the required bit forces y above x, we're free to minimize the rest.
      // If at some point the required bit forces y below x (required 1 but x has 1 and we
      // need to set 0... no, required bits are always 1, so if target bit is 1, y bit is 1.
      // If target bit is 0, y bit is free.

      // Cases at each bit position (processing from MSB to LSB):
      // State: "equal" (y prefix == x prefix so far) or "greater" (y prefix > x prefix)
      //
      // If "greater": set y bit to target bit (forced 1 if target, else 0 to minimize)
      // If "equal":
      //   If target bit = 1:
      //     If x bit = 1: y bit = 1, stay "equal"
      //     If x bit = 0: y bit = 1, become "greater"
      //   If target bit = 0 (free):
      //     Try y bit = x bit first (stay "equal")
      //     (If later we find it's impossible to satisfy, backtrack to y bit = 1 -> "greater")

      // But we might not need backtracking if we're careful. Actually for this problem,
      // since free bits can be anything and required bits are 1:
      // When "equal" and target bit = 0, if x bit = 0, set y = 0, stay equal.
      //   If x bit = 1, set y = 1, stay equal.
      // When "equal" and target bit = 1, if x bit = 1, set y = 1, stay equal.
      //   If x bit = 0, set y = 1, now "greater", minimize rest.

      // The issue is: when equal and target = 0 and x = 1, we set y = 1 to stay equal.
      // But what if later a target bit is 1 and x bit is 0? Then y becomes greater at that point.
      // That's fine - y is still valid.

      // Wait, the problematic case is: equal, target bit = 0, x bit = 1. We set y = 1.
      // But later: equal, target bit = 1, x bit = 1. We set y = 1, still equal.
      // And then: equal, target bit = 0, x bit = 1, and the remaining bits can't satisfy.
      // Hmm no, free bits can always be set to match x, so "equal" path always works until
      // a forced bit differs from x. If forced bit = 1 and x bit = 0, we go to "greater"
      // (good, y > x). If forced bit = 1 and x bit = 1, stay equal. If free bit, match x.
      //
      // So actually the "equal" path never fails - we either stay equal or become greater.
      // We never need y bit < x bit because required bits are 1 (>= any x bit of 0, = x bit of 1).
      // And free bits match x.

      // So the greedy algorithm works without backtracking!

      let mut y = 0i64;
      let mut state = 0; // 0 = equal, 1 = greater
      for b in (0..31).rev() {
        let target_bit = (target >> b) & 1;
        let x_bit = (x >> b) & 1;
        if state == 1 {
          // Already greater, minimize: set to target_bit
          y |= target_bit << b;
        } else {
          // Equal so far
          if target_bit == 1 {
            y |= 1 << b;
            if x_bit == 0 {
              state = 1; // now greater
            }
          } else {
            // Free bit, match x to stay equal
            y |= x_bit << b;
          }
        }
      }
      y - x
    };

    let mut answer = 0i32;

    // Try to build answer from highest bit to lowest
    // At each step, try to set the current bit. Check if we can achieve (answer | bit)
    // with at most m elements and cost <= k.

    for bit in (0..31).rev() {
      let candidate = answer | (1 << bit);
      let target = candidate as i64;

      // Compute cost for each element to reach target, pick m smallest
      let mut costs: Vec<i64> = nums.iter().map(|&x| cost_to_reach(x as i64, target)).collect();
      costs.sort_unstable();

      let total: i64 = costs.iter().take(m).sum();
      if total <= k {
        answer = candidate;
      }
    }

    answer
  }
}