Minimize XOR with power of 2 to make elements in range equal
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.
- Calculate the number of set bits in each position in the range lth to rth.
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
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)
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)
Please Login to comment...