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++ 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 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.
# 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# 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 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++ 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 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
# 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# 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 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)