Open In App

Minimize XOR with power of 2 to make elements in range equal

Last Updated : 07 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array A[] of size N (0 ? A[i] ? 109). The following operations can be performed on the array.

  • Choose a random integer X such that it is a power of 2.
  • Choose an index from 0 to N-1 and replace A[i] with A[i] ? X, where, ? represent the binary XOR operation.

The task is to answer Q queries where each query is of type [l, r] denoting the range from lth to rth index (both inclusive) and you have to find the minimum operations to make all the elements in the range equal.

Examples:

Input: N = 4, A[] = {2, 3, 1, 7}, Q = 1, query[]= {{0, 2}}
Output: 2
Explanation: The operations are as follows:
Choose X = 1 and A[0] = 2. Array becomes {3, 3, 1, 7}.
Choose X = 2 and A[2] = 1. Array becomes {3, 3, 3, 7}.
Hence the subarray between index 0 and 2 becomes equal.   

Approach:

In one operation we can change only one bit of a single element because X is power of 2. So the task is to find the number of bits that need to be set between the given ranges.

Follow the steps mentioned below to implement the idea:

  • Try to solve this problem by considering each bit position separately as all the elements are equal at the end and have the same binary representation.
  • For a given query with range [l, r], total number of elements n = (r-l+1).
    • Calculate the number of set bits in each position in the range lth to rth
      • Then we have two options either make this bit position 1 or 0 in the final binary representation 
      • Let x be the number of set bits for an ith position. Then the minimum number of operations for making this bit equal in all elements in the given range is minimum(x, n – x).
    • Thus, the answer for the given query will be the summation of minimum(x, n – x) over 1st to 32nd.

Below is  the implementation of the above approach.

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate minimum operation
vector<int> MinimumOperations(int N, int A[], int Q,
                              int query[][2])
{
    // Vector to store ans of all queries
    vector<int> ans;
 
    // Loop to calculate the minimum number
    // of operations for each query
    for (int i = 0; i < Q; i++) {
        int l = query[i][0];
        int r = query[i][1];
 
        // To store answer for current query
        int y = 0;
        int n = (r - l + 1);
 
        // loop for calculating at
        // number of setbits from
        // 0th to 31st bit
        for (int j = 0; j < 32; j++) {
            int setbitcount = 0;
            for (int i = l; i <= r; i++) {
                int mask = pow(2, j);
                if (A[i] & mask)
                    setbitcount++;
            }
            y += min(setbitcount, n - setbitcount);
        }
 
        ans.push_back(y);
    }
    return ans;
}
 
// Driver code
int main()
{
    int A[] = { 2, 3, 1, 7 };
    int N = sizeof(A) / sizeof(A[0]);
    int query[][2] = { { 0, 2 } };
 
    // Function call
    vector<int> v = MinimumOperations(N, A, 1, query);
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
    return 0;
}


Java




// Java code to implement the approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
  // Function to calculate minimum operation
  static List<Integer>
    MinimumOperations(int N, int[] A, int Q, int[][] query)
  {
    // arraylist to store ans of all queries
    List<Integer> ans = new ArrayList<Integer>();
 
    // Loop to calculate the minimum number
    // of operations for each query
    for (int i = 0; i < Q; i++) {
      int l = query[i][0];
      int r = query[i][1];
 
      // To store answer for current query
      int y = 0;
      int n = (r - l + 1);
 
      // loop for calculating at
      // number of setbits from
      // 0th to 31st bit
      for (int j = 0; j < 32; j++) {
        int setbitcount = 0;
        for (int k = l; k <= r; k++) {
          int mask = (int)Math.pow(2, j);
          if ((A[k] & mask) == 1) {
            setbitcount++;
          }
        }
        y += Math.min(setbitcount, n - setbitcount);
      }
      ans.add(y);
    }
    return ans;
  }
 
  public static void main(String[] args)
  {
    int[] A = { 2, 3, 1, 7 };
    int N = A.length;
    int[][] query = { { 0, 2 } };
 
    // Function call
    List<Integer> v = MinimumOperations(N, A, 1, query);
    for (int i = 0; i < v.size(); i++) {
      System.out.print(v.get(i) + " ");
    }
  }
}
 
// This code is contributed by lokeshmvs21.


Python3




# Python code to implement the approach
 
# Function to calculate minimum operation
def MinimumOperations(N, A, Q, query):
    # List to store ans of all queries
    ans = []
     
    # Loop to calculate the minimum number
    # of operations for each query
    for i in range(Q):
        l = query[i][0]
        r = query[i][1]
         
        # To store answer for current query
        y = 0
        n = r - l + 1
         
        # loop for calculating at
        # number of setbits from
        # 0th to 31st bit
        for j in range(32):
            setbitcount = 0
            for i in range(l, r + 1):
                mask = 2**j
                if(A[i]&mask):
                    setbitcount = setbitcount + 1
            y=y+min(setbitcount, n - setbitcount)
         
        ans.append(y)
     
    return ans
 
# Driver code
 
A = [2, 3, 1, 7]
N = len(A)
query = [[0, 2]]
 
# Function call
v=MinimumOperations(N, A, 1, query)
for i in range(len(v)):
    print(v[i], end=" ")
 
# This code is contributed by Pushpesh Raj.


C#




// C# code addition
using System;
 
public class GFG {
 
  // Function to calculate minimum operation
  public static int[] MinimumOperations(int N, int[] A,
                                        int Q,
                                        int[, ] query)
  {
    // Vector to store ans of all queries
    int[] ans = new int[Q];
 
    // Loop to calculate the minimum number
    // of operations for each query
    for (int i = 0; i < Q; i++) {
      int l = query[i, 0];
      int r = query[i, 1];
 
      // To store answer for current query
      int y = 0;
      int n = (r - l + 1);
 
      // loop for calculating at
      // number of setbits from
      // 0th to 31st bit
      for (int j = 0; j < 32; j++) {
        int setbitcount = 0;
        for (int k = l; k <= r; k++) {
          int mask = (int)Math.Pow(2, j);
          if ((A[k] & mask) == 0)
            setbitcount++;
        }
        y += Math.Min(setbitcount, n - setbitcount);
      }
 
      ans[i] = y;
    }
    return ans;
  }
 
  static public void Main()
  {
 
    int[] A = { 2, 3, 1, 7 };
 
    int N = A.Length;
    int[, ] query = { { 0, 2 } };
 
    // Function call
    int[] v = MinimumOperations(N, A, 1, query);
    for (int i = 0; i < v.Length; i++) {
      Console.WriteLine(v[i]);
    }
  }
}
 
// This code is contributed by ksam24000


Javascript




   // JavaScript code for the above approach
 
   // Function to calculate minimum operation
   function MinimumOperations(N, A, Q,
     query) {
     // Vector to store ans of all queries
     let ans = [];
 
     // Loop to calculate the minimum number
     // of operations for each query
     for (let i = 0; i < Q; i++) {
       let l = query[i][0];
       let r = query[i][1];
 
       // To store answer for current query
       let y = 0;
       let n = (r - l + 1);
 
       // loop for calculating at
       // number of setbits from
       // 0th to 31st bit
       for (let j = 0; j < 32; j++) {
         let setbitcount = 0;
         for (let i = l; i <= r; i++) {
           let mask = Math.pow(2, j);
           if (A[i] & mask)
             setbitcount++;
         }
         y += Math.min(setbitcount, n - setbitcount);
       }
 
       ans.push(y);
     }
     return ans;
   }
 
   // Driver code
 
   let A = [2, 3, 1, 7];
   let N = A.length;
   let query = [[0, 2]];
 
   // Function call
   let v = MinimumOperations(N, A, 1, query);
   for (let i = 0; i < v.length; i++) {
     console.log(v[i] + " ");
   }
 
// This code is contributed by Potta Lokesh


Output

2 

Time Complexity: O(Q*N*32) For every query, we are iterating all the elements in the range [l, r] and we are iterating 32 times.
Auxiliary Space: O(Q)

Efficient Approach using Prefix sum:

The above approach can be optimized by creating a prefix array (say dp[][]) where dp[i][j] will store the total number of setbits at jth position till ith index.

Follow the steps mentioned below to implement the idea:

  • Maintain a dp[][] array to store the number of setbits at jth position till ith index from the starting.
  • So for a given query with range [l, r], the number of setbits at jth position can be calculated in constant time.
  • Use this modification in the approach mentioned earlier to calculate the setbit count and the problem can be solved in linear time.

Below is the implementation of the above approach.

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate minimum operation
vector<int> MinimumOperations(int N, int A[], int Q,
                              int query[][2])
{
    // dp array where dp[i][j] stores
    // the number of setbits
    // in first i elements at j position
    int dp[N + 1][32];
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < 32; j++) {
            if (A[i] & (1 << j)) {
                dp[i + 1][j] = 1;
            }
        }
    }
 
    // Loop to build the prefix sum array
    for (int i = 2; i <= N; i++) {
        for (int j = 0; j < 32; j++) {
            dp[i][j] = dp[i][j] + dp[i - 1][j];
        }
    }
    vector<int> ans;
 
    // Loop to solve the queries
    for (int i = 0; i < Q; i++) {
        int l = query[i][0], r = query[i][1];
        int y = 0, n = (r - l + 1);
        for (int j = 0; j < 32; j++) {
 
            // Number of setbits in r-l+1 elements
            // at jth position
            int x = dp[r + 1][j] - dp[l][j];
            y += min(x, n - x);
        }
        ans.push_back(y);
    }
    return ans;
}
 
// Driver code
int main()
{
    int A[] = { 2, 3, 1, 7 };
    int N = sizeof(A) / sizeof(A[0]);
    int query[][2] = { { 0, 2 } };
 
    // Function call
    vector<int> v = MinimumOperations(N, A, 1, query);
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
    return 0;
}


Java




// Java code to implement the approach
import java.util.*;
 
class HelloWorld {
 
  // Function to calculate minimum operation
  static ArrayList<Integer>
    MinimumOperations(int N, int A[], int Q, int query[][])
  {
    // dp array where dp[i][j] stores
    // the number of setbits
    // in first i elements at j position
    int[][] dp = new int[N + 1][32];
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < 32; j++) {
        if ((A[i] & (1 << j)) != 0) {
          dp[i + 1][j] = 1;
        }
      }
    }
 
    // Loop to build the prefix sum array
    for (int i = 2; i <= N; i++) {
      for (int j = 0; j < 32; j++) {
        dp[i][j] = dp[i][j] + dp[i - 1][j];
      }
    }
    ArrayList<Integer> ans = new ArrayList<>();
 
    // Loop to solve the queries
    for (int i = 0; i < Q; i++) {
      int l = query[i][0], r = query[i][1];
      int y = 0, n = (r - l + 1);
      for (int j = 0; j < 32; j++) {
 
        // Number of setbits in r-l+1 elements
        // at jth position
        int x = dp[r + 1][j] - dp[l][j];
        y += Math.min(x, n - x);
      }
      ans.add(y);
    }
    return ans;
  }
 
  // Driver code
  public static void main(String[] args)
  {
    int A[] = { 2, 3, 1, 7 };
    int N = A.length;
    int query[][] = { { 0, 2 } };
 
    // Function call
    ArrayList<Integer> v
      = MinimumOperations(N, A, 1, query);
    for (int i = 0; i < v.size(); i++) {
      System.out.print(v.get(i) + " ");
    }
  }
}
 
// This code is contributed by karandeep1234


Python3




# Python code to implement the approach
 
# Function to calculate minimum operation
def MinimumOperations(N, A, Q, query):
 
    # dp array where dp[i][j] stores
    # the number of setbits
    # in first i elements at j position
    dp = [[0 for i in range(32)]
          for j in range(N + 1)]
    for i in range(N):
        for j in range(32):
            if (A[i] & (1 << j)):
                dp[i + 1][j] = 1
 
    # Loop to build the prefix sum array
    for i in range(2, N + 1):
        for j in range(32):
            dp[i][j] = dp[i][j] + dp[i - 1][j]
    ans = []
 
    # Loop to solve the queries
    for i in range(Q):
        l = query[i][0]
        r = query[i][1]
        y = 0
        n = (r - l + 1)
        for j in range(32):
 
            # Number of setbits in r-l+1 elements
            # at jth position
            x = dp[r + 1][j] - dp[l][j]
            y += min(x, n - x)
        ans.append(y)
    return ans
 
 
# Driver code
A = [2, 3, 1, 7]
N = len(A)
query = [[0, 2]]
 
# Function call
v = MinimumOperations(N, A, 1, query)
for i in range(len(v)):
    print(v[i], end=" ")
 
# This code is contributed by Tapesh(tapeshdua420)


C#




// C# program to implement the approach
using System;
using System.Collections.Generic;
 
class GFG {
 
    // Function to calculate minimum operation
    static List<int> MinimumOperations(int N, int[] A,
                                       int Q, int[][] query)
    {
 
        // dp array where dp[i][j] stores
        // the number of setbits
        // in first i elements at j position
        int[, ] dp = new int[N + 1, 32];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < 32; j++) {
                if ((A[i] & (1 << j)) != 0) {
                    dp[i + 1, j] = 1;
                }
            }
        }
 
        // Loop to build the prefix sum array
        for (int i = 2; i <= N; i++) {
            for (int j = 0; j < 32; j++) {
                dp[i, j] = dp[i, j] + dp[i - 1, j];
            }
        }
        List<int> ans = new List<int>();
 
        // Loop to solve the queries
        for (int i = 0; i < Q; i++) {
            int l = query[i][0], r = query[i][1];
            int y = 0, n = (r - l + 1);
            for (int j = 0; j < 32; j++) {
 
                // Number of setbits in r-l+1 elements
                // at jth position
                int x = dp[r + 1, j] - dp[l, j];
                y += Math.Min(x, n - x);
            }
            ans.Add(y);
        }
        return ans;
    }
 
    // Driver code
    public static void Main()
    {
        int[] A = { 2, 3, 1, 7 };
        int N = A.Length;
        int[][] query = { new int[] { 0, 2 } };
 
        // Function call
        List<int> v = MinimumOperations(N, A, 1, query);
        for (int i = 0; i < v.Count; i++) {
            Console.Write(v[i] + " ");
        }
    }
}
 
// This code is contributed by Tapesh(tapeshdua420)


Javascript




// Javascript code to implement the approach
 
// Function to calculate minimum operation
function MinimumOperations(N, A, Q, query)
{
     
    // dp array where dp[i][j] stores
    // the number of setbits
    // in first i elements at j position
    var dp = new Array(N + 1);
    for (var i = 0; i <= N; i++) {
        dp[i] = new Array(32);
        for (var j = 0; j < 32; j++) {
            dp[i][j] = 0;
        }
    }
     
    for (var i = 0; i < N; i++)
        for (var j = 0; j < 32; j++)
            if ((A[i] & (1 << j)))
                dp[i + 1][j] = 1;
     
    // Loop to build the prefix sum array
    for (var i = 2; i < N + 1; i++)
        for (var j = 0; j < 32; j++)
            dp[i][j] = dp[i][j] + dp[i - 1][j];
    var ans = [];
     
    // Loop to solve the queries
    for (var i = 0; i < Q; i++)
    {
        var l = query[i][0];
        var r = query[i][1];
        var y = 0;
        var n = (r - l + 1);
        for (var j = 0; j < 32; j++)
        {
             
            // Number of setbits in r-l+1 elements
            // at jth position
            var x = dp[r + 1][j] - dp[l][j];
            y += Math.min(x, n - x);
        }
        ans.push(y);
    }
    return ans;
}
 
// Driver code
var A = [2, 3, 1, 7];
var N = A.length;
var query = [[0, 2]];
 
// Function call
var v = MinimumOperations(N, A, 1, query);
for (var i = 0; i < v.length; i++)
    process.stdout.write(v[i]+" ");
 
// This code is contributed by Tapesh(tapeshdua420)


Output

2 

Time Complexity: O( 32 * (Q + N)) It takes 32*N to create the prefix sum array and 32*Q to answer the queries
Auxiliary Space: O(32 * N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads