MAXXORSUM - Editorial

Author: agrawall117
Testers: nishant403, satyam_343
Editorialist: iceknight1093

TBD

PREREQUISITES:

Familiarity with bitwise operations

PROBLEM:

You have two arrays A and B of length N. An array X is said to be good if it satisfies

A_i = X_1 \mid X_2 \mid \ldots \mid X_i \\ B_i = X_i \ \& \ X_{i+1} \ \& \ \ldots \ \&\ X_N \\

for every i from 1 to N.
Find the maximum value of X_1\oplus X_2\oplus\ldots\oplus X_N across all good arrays.

EXPLANATION:

Since everything’s a bitwise operation, let’s look at each bit separately and check whether we can add this bit to our bitwise XOR.

Consider a fixed bit b. We only need to care about whether b is set or not in each A_i and B_i.
So, we can treat A and B as boolean arrays corresponding to this bit.

Now, let’s use the fact that A is prefix OR and B is suffix AND to deduce some properties about which X_i have bit b set.
Since the input guarantees that at least one valid X exists, A and B both look like [0, 0, 0, \ldots, 0, 1, 1,1, \ldots, 1] (i.e, some zeros followed by some ones). Of course, they might have different numbers of ones and zeros.
Now,

• If B_i = 1, then all of X_i, X_{i+1}, \ldots, X_N must have bit b set.
• If B_i = 0, then at least one of X_i, \ldots, X_N must have b unset.
• In particular, if B_i = 0 and B_{i+1} = 1, then X_i must have b unset, and X_{i+1}, \ldots, X_N will all have it set. So, X_i is the last time it’s unset.
• Similar analysis will tell you that if A_i = 0 and A_{i+1} = 1, then X_{i+1} must have b set; while X_1, X_2, \ldots, X_{i} all have it unset. So, X_i is the first time it’s set.

Let \text{first}_b be the first position i such that X_i has bit b set, and \text{last}_b be the last position where it’s unset. These can be found as described above.

Let’s do a bit of casework:

• If \text{last}_b+1 = \text{first}_b, then we know that exactly some suffix of X (specifically, the one starting from \text{first}_b) contains bit b. Depending on the length of this suffix (odd/even), the final XOR will either contain bit b or not.
• If \text{first}_b+1 = \text{last}_b, then the suffix of X starting at \text{last}_b+1 contains bit b, as well as position \text{first}_b. Once again, we know exactly how many occurrences there are, so we can tell uniquely whether the answer contains bit b or not.
• Otherwise, \text{first}_b \lt \text{last}_b. In this case, the positions between \text{first}_b+1 and \text{last}_b-1 are ‘free’, i.e, for each one we can freely decide whether this X_i contains bit b.
In particular, we can always make the number of occurrences odd, so we can ensure that the answer will always contain bit b.

Processing a single bit takes \mathcal{O}(N) time, so we have a solution in \mathcal{O}(30\cdot N).

TIME COMPLEXITY:

\mathcal{O}(N) per testcase.

CODE:

Tester's code (C++)
using namespace std;

/*
------------------------Input Checker----------------------------------
*/

long long readInt(long long l,long long r,char endd){
long long x=0;
int cnt=0;
int fi=-1;
bool is_neg=false;
while(true){
char g=getchar();
if(g=='-'){
assert(fi==-1);
is_neg=true;
continue;
}
if('0'<=g && g<='9'){
x*=10;
x+=g-'0';
if(cnt==0){
fi=g-'0';
}
cnt++;
assert(fi!=0 || cnt==1);
assert(fi!=0 || is_neg==false);

assert(!(cnt>19 || ( cnt==19 && fi>1) ));
} else if(g==endd){
if(is_neg){
x= -x;
}

if(!(l <= x && x <= r))
{
cerr << l << ' ' << r << ' ' << x << '\n';
assert(1 == 0);
}

return x;
} else {
assert(false);
}
}
}
string ret="";
int cnt=0;
while(true){
char g=getchar();
assert(g!=-1);
if(g==endd){
break;
}
cnt++;
ret+=g;
}
assert(l<=cnt && cnt<=r);
return ret;
}
long long readIntSp(long long l,long long r){
}
long long readIntLn(long long l,long long r){
}
}
}

/*
------------------------Main code starts here----------------------------------
*/

const int MAX_T = 1e5;
const int MAX_N = 1e5;
const int MAX_SUM_N = 3e5;
const int BIT = 30;
const int MAX_VAL = (1 << BIT);

#define fast ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)

int sum_n = 0;
int max_n = 0;
int max_ans = 0;

void solve()
{
int n;

max_n = max(max_n, n);
sum_n += n;
assert(sum_n <= MAX_SUM_N);

int a[n];
for(int i=0;i<n;i++) {
if(i != n - 1) {
} else {
}
}

int b[n];
for(int i=0;i<n;i++) {
if(i != n - 1) {
} else {
}
}

int ans = 0;

for(int i=0;i<BIT;i++) {
int bit_val[n];

// -1 means can be 0/1
for(int j=0;j<n;j++) {
bit_val[j] = -1;
}

bool found_1_a = false;

for(int j=0;j<n;j++) {
if((a[j] >> i) & 1) {
if(found_1_a == false) {
bit_val[j] = 1;
found_1_a = true;
}
} else {
assert(found_1_a == false);
bit_val[j] = 0;
}
}

bool found_0_b = false;

for(int j=n-1;j>=0;j--) {
if(!((b[j] >> i) & 1)) {
if(found_0_b == false) {
assert(bit_val[j] != 1);
found_0_b = true;
bit_val[j] = 0;
}
} else {
assert(found_0_b == false);
assert(bit_val[j] != 0);
bit_val[j] = 1;
}
}

int can_change = 0;
int cur_xor = 0;

for(int j=0;j<n;j++) {
if(bit_val[j] == 1) cur_xor ^= 1;
else if(bit_val[j] == -1) can_change = 1;
}

if(can_change || cur_xor) ans |= (1 << i);
}

max_ans = max(max_ans , ans);

cout << ans << '\n';
}

signed main()
{
int t = 1;

for(int i=1;i<=t;i++)
{
solve();
}

assert(getchar() == -1);

cerr<<"SUCCESS\n";
cerr<<"Tests : " << t << '\n';
cerr<<"Sum of lengths : " << sum_n << '\n';
cerr<<"Maximum length : " << max_n << '\n';
cerr<<"Maximum answer : " << max_ans << '\n';
}

Editorialist's code (Python)
import sys
for _ in range(int(input())):
n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
first_1 = [-1]*31
last_1 = [n]*31
for i in range(n):
for bit in range(30):
if a[i] & (1 << bit) and first_1[bit] == -1: first_1[bit] = i
if b[i] & (1 << bit) and last_1[bit] == n: last_1[bit] = i
ans = 0
for i in range(31):
L, R = first_1[i], last_1[i]
if L == -1: continue
if L == R:
if (n-R)%2: ans += 2**i
elif L+2 == R:
if (n-R)%2 == 0: ans += 2**i
else: ans += 2**i
print(ans)