At bit level it is simple 0 XOR 0, 1 XOR 1 = 0
and last one 0 XOR 1 = 1
, but when these bit belongs to a number XOR operations have addition and subtraction effect. For example if third
bit of a number is set and num XOR with 4 (0100)
which also have third
bit set then result would be subtraction
from number by 2^(3-1)
, for example num = 5
then 0101 XOR 0100 = 0001
, 4
subtracted
in 5
, Similarly if third
bit of a number is not set and num XOR with 4
then result would be addition
for example num = 2
then 0010 XOR 0100 = 0101
, 4
will be added in 2
. Now let’s see this problem,
This problem can’t be solved by applying XOR on each number individually, rather the approach to solve this problem is Perform XOR on particular bit of all numbers, in one go!
. Let’s see how it can be done?
Fact 1: Let’s consider we have X
and we want to perform XOR on all numbers
with X
and if we know second
bit of X
is set, now suppose somehow we also know that how many numbers
in all numbers
have second
bit set then we know answer 1 XOR 1 = 0
and we don’t
have to perform XOR
on each number individually
.
Fact 2: From fact 1
, we know how many numbers
have a particular bit set, let’s call it M
and if X
also have that particular bit set then M * 2^(pos -1)
will be subtracted
from sum of all numbers
. If N
is total element in array than N - M
numbers don’t
have that particular bit set and due to it (N – M) * 2^(pos-1)
will be added
in sum of all numbers
.
From Fact 1
and Fact 2
we can calculate overall XOR effect
on a particular bit
on all Numbers
by effect = (N – M)* 2^(pos -1) – (M * 2^(pos -1))
and can perform the same for all bits.
Now it’s time to see above theory in action, if we have array = {1, 6, 3}
, k = 7
then,
1 = 0001 (There are total 32 bits but I am showing only relevant bits other bits are zero)
6 = 0110
3 = 0011
So our bit count
list = [0, 1, 2, 2]
as you can see 1
and 3
have first
bit set, 6
and 3
have second
bit set and only 6
have third
bit set.
X = 0, …, 7
but X = 0
have effect = 0
on sum
because if bit is not set then it doesn’t not affect other bit in XOR operation, so let’s star from X = 1
which is 0001
,
[0, 1, 2, 2] = count list,
[0, 0, 0, 1] = X
As it is visible in count list
two numbers have first
bit set and X
also have first
bit set, it means 2 * 2^(1 – 1)
will be subtract
in sum and total numbers in array
are three
, so (3 – 2) * 2^(1-1)
will be added
in sum. Conclusion is XOR of first bit is, effect = (3 – 2) * 2^(1-1) - 2 * 2^(1 – 1) = 1 – 2 = -1
. It is also overall effect by X = 1
because it only has first
bit set and rest of bits are zero. At this point we compare effect
produced by X = 1
with X = 0
and -1 < 0
which means X = 1
will reduce sum of all numbers
by -1
but X = 0
will not
deduce sum of all numbers. So until now X = 0
will produce max sum.
The way XOR is performed for X = 1
can be performed for all other values and I would like to jump directly to X = 4
which is 0100
[0, 1, 2, 2] = count list,
[0, 1, 0, 0] = X
As it is visible X
have only third
bit set and only one
number in array have first
bit set, it means 1 * 2^(3 – 1 )
will be subtracted
and (3 – 1) * 2^(3-1)
will be added
and overall effect = (3 – 1) * 2^(3-1) - 1 * 2^(3 – 1 ) = 8 – 4 = 4
. At this point we compare effect
of X = 4
with known max effect
which is effect = 0
so 4 > 0
and due to this X = 4
will produce max sum
and we considered it. When you perform this for all X = 0,…,7
, you will find X = 4
will produce max effect
on sum
, so the answer is X = 4
.
So
(x XOR arr[0]) + ( x XOR arr[1]) +….. + (x XOR arr[n]) = effect + sum(arr[0] + sum[1]+ …. + arr[n])
Complexity is,
O(32 n)
to find for all 32 bits
, how many number
have a particular bit set, plus
,
O(32 k)
to find effect
of all X
in [0, k]
,
Complexity = O(32 n) + O(32 k) = O(c n) + O(c k)
, here c
is constant,
finally
Complexity = O(n)
#include <iostream>
#include <cmath>
#include <bitset>
#include <vector>
#include <numeric>
std::vector<std::uint32_t> bitCount(const std::vector<std::uint32_t>& numList){
std::vector<std::uint32_t> countList(32, 0);
for(std::uint32_t num : numList){
std::bitset<32> bitList(num);
for(unsigned i = 0; i< 32; ++i){
if(bitList[i]){
countList[i] += 1;
}
}
}
return countList;
}
std::pair<std::uint32_t, std::int64_t> prefXAndMaxEffect(std::uint32_t n, std::uint32_t k,
const std::vector<std::uint32_t>& bitCountList){
std::uint32_t prefX = 0;
std::int64_t xorMaxEffect = 0;
std::vector<std::int64_t> xorBitEffect(32, 0);
for(std::uint32_t x = 1; x<=k; ++x){
std::bitset<32> xBitList(x);
std::int64_t xorEffect = 0;
for(unsigned i = 0; i< 32; ++i){
if(xBitList[i]){
if(0 != xorBitEffect[i]){
xorEffect += xorBitEffect[i];
}
else{
std::int64_t num = std::exp2(i);
xorBitEffect[i] = (n - bitCountList[i])* num - (bitCountList[i] * num);
xorEffect += xorBitEffect[i];
}
}
}
if(xorEffect > xorMaxEffect){
prefX = x;
xorMaxEffect = xorEffect;
}
}
return {prefX, xorMaxEffect};
}
int main(int , char *[]){
std::uint32_t k = 7;
std::vector<std::uint32_t> numList{1, 6, 3};
std::pair<std::uint32_t, std::int64_t> xAndEffect = prefXAndMaxEffect(numList.size(), k, bitCount(numList));
std::int64_t sum = 0;
sum = std::accumulate(numList.cbegin(), numList.cend(), sum) + xAndEffect.second;
std::cout<< sum<< '\n';
}
Output :
14