Twin Clusters (Codeforces 1836E)
Tags: Others, meet-in-the-middle

Famous worldwide astrophysicist Mleil waGrasse Tysok recently read about the existence of twin galaxy clusters. Before he shares this knowledge with the broader audience in his podcast called S.tarT-ok, he wants to prove their presence on his own. Mleil is aware that the vastness of the universe is astounding (almost as astounding as his observation skills) and decides to try his luck and find some new pair of twin clusters.To do so, he used his TLEscope to observe a part of the night sky that was not yet examined by humanity in which there are exactly $$$2^{k + 1}$$$ galaxies in a row. $$$i$$$-th of them consist of exactly $$$0 \le g_i < 4^k$$$ stars.A galaxy cluster is any non-empty contiguous segment of galaxies. Moreover, its' trait is said to be equal to the bitwise XOR of all values $$$g_i$$$ within this range.Two galaxy clusters are considered twins if and only if they have the same traits and their corresponding segments are disjoint.Write a program that, for many scenarios, will read a description of a night sky part observed by Mleil and outputs a location of two intervals belonging to some twin clusters pair, or a single value $$$-1$$$ if no such pair exists.

Input: The first line contains a single integer $$$t$$$, denoting the number of test cases that the program has to handle. The following lines contain test case descriptions, each containing exactly two lines.The first of them contains a single integer $$$k$$$ ($$$0 \le k \le 17$$$).The second line contains $$$2^{k + 1}$$$ integers $$$g_1, g_2, \ldots, g_{2^{k+1}}$$$ ($$$0 \le g_i < 4^k$$$).We guarantee that the sum of values $$$2^{k + 1}$$$ over all test cases does not exceed $$$2^{18}$$$.

Output: Answers for all test cases should be present in separate lines. If there exist a pair of twin galaxies, then output four integers $$$a$$$, $$$b$$$, $$$c$$$, and $$$d$$$ denoting their inclusive ranges $$$[a, b]$$$ and $$$[c, d]$$$ (the first interval does not need to start before the second one, but they have to be disjoint). If no pair of such galaxies exist, output a single value $$$-1$$$ instead.

Note: In the first test case we pick intervals $$$[2, 4]$$$ and $$$[6, 6]$$$ as our twin clusters. The trait of the first interval equals $$$15 \oplus 0 \oplus 7 = 8$$$, and the trait of the second interval equals $$$8$$$, so these galaxy clusters are indeed twins.

Sample Inputs:
4
2
4 15 0 7 11 8 3 2
1
0 1 2 3
0
0 0
3
15 63 57 39 61 25 42 61 50 41 27 41 56 23 17 27

Sample Outputs:
2 4 6 6
2 2 3 4
1 1 2 2
1 1 4 10

Solution (Python):
from random import randrange

def solve(k, g):
    present = {}
    for (i, ele) in enumerate(g):
        if ele in present:
            return (present[ele] + 1, present[ele] + 1, i + 1, i + 1)
        else:
            present[ele] = i
    prefix_sum = [0]
    for (i, ele) in enumerate(g):
        prefix_sum.append(prefix_sum[-1] ^ ele)

    def range_xor(a, b):
        return prefix_sum[a] ^ prefix_sum[b + 1]
    xors = {}
    while True:
        (a, b) = (randrange(len(g)), randrange(len(g)))
        if a > b:
            (a, b) = (b, a)
        z = range_xor(a, b)
        if z not in xors:
            xors[z] = (a, b)
        else:
            (c, d) = xors[z]
            if a == c or b == d:
                continue
            if a > c:
                (a, b, c, d) = (c, d, a, b)
            if c > b:
                return (a + 1, b + 1, c + 1, d + 1)
            else:
                if d < b:
                    return (a + 1, c, d + 2, b + 1)
                return (a + 1, c, b + 2, d + 1)
t = int(input())
for _ in range(t):
    k = int(input())
    g = [int(component) for component in input().split(' ')]
    print(' '.join((str(c) for c in solve(k, g))))

Solution (Python):
import sys
import collections
rd = sys.stdin.readline
t = int(rd())
for _ in range(t):
    k = int(rd())
    arr = list(map(int, rd().split()))
    xor = [0]
    xorhalf = [0]
    idx = collections.defaultdict(int)
    idx[0] = 0
    pos = []
    for i in range(len(arr)):
        a = arr[i]
        xor.append(xor[-1] ^ a)
        xorhalf.append(xor[-1] % (1 << k))
        if xorhalf[-1] in idx:
            pos.append([idx[xorhalf[-1]] + 1, i + 1])
        idx[xorhalf[-1]] = i + 1
    num = collections.defaultdict(int)
    for i in range(len(pos)):
        (x, y) = pos[i]
        m = xor[y] ^ xor[x - 1]
        if m in num:
            (a, b, c, d) = (x, y, pos[num[m]][0], pos[num[m]][1])
            break
        num[m] = i
    if a > c:
        (a, b, c, d) = (c, d, a, b)
    if b >= c and b < d:
        (b, c) = (c - 1, b + 1)
    elif b > d:
        (b, c, d) = (c - 1, d + 1, b)
    print(a, b, c, d)

Solution (Python):
import collections
import sys
import heapq
input = sys.stdin.readline

def inp():
    return int(input())

def inlt():
    return list(map(int, input().split()))

def insr():
    s = input()
    return list(s[:len(s) - 1])

def invr():
    return map(int, input().split())

def solution():
    k = inp()
    galaxies = inlt()
    n = 2 << k
    pre_xor = [0]
    for num in galaxies:
        pre_xor.append(pre_xor[-1] ^ num)
    mem_high_bits = [-1] * (1 << k)
    mem_high_bits[0] = 0
    mem_low_bits = [(-1, -1) for _ in range(1 << k)]
    for i in range(1, n + 1):
        if mem_high_bits[pre_xor[i] >> k] != -1:
            whole_xor = pre_xor[mem_high_bits[pre_xor[i] >> k]] ^ pre_xor[i]
            (start, end) = mem_low_bits[whole_xor]
            if start == -1:
                mem_low_bits[whole_xor] = (mem_high_bits[pre_xor[i] >> k], i)
            else:
                if end < mem_high_bits[pre_xor[i] >> k] + 1:
                    print(f'{start + 1} {end} {mem_high_bits[pre_xor[i] >> k] + 1} {i}')
                else:
                    print(f'{min(start + 1, mem_high_bits[pre_xor[i] >> k] + 1)} {max(start + 1, mem_high_bits[pre_xor[i] >> k] + 1) - 1} {end + 1} {i}')
                return
        mem_high_bits[pre_xor[i] >> k] = i
if __name__ == '__main__':
    t = inp()
    for i in range(t):
        solution()