← Все вопросы

Как на бинарном боре найти максимальный XOR пары чисел из массива?

Задан 22 месяца назад545 просмотров2 ответа
10

Классическая задача: дан массив, найти максимум a[i] XOR a[j]. Наивно O(n^2). Везде советуют «бинарный бор по битам». Не понимаю, как уложить числа в бор и почему жадный спуск даёт максимум.

2 ответа

15
✓ Принятый ответ — помог автору

Числа кладём в бор как двоичные строки фиксированной длины (например 30 бит), старший бит — у корня. Чтобы максимизировать XOR с запрашиваемым числом, на каждом бите жадно пытаемся пойти в противоположный бит — тогда в этом разряде XOR даст 1, что весомее всех младших разрядов вместе.

struct XorTrie {
    static const int B = 30;
    vector<array<int,2>> t{{ -1,-1 }};
    void insert(int x) {
        int v = 0;
        for (int b = B; b >= 0; --b) {
            int bit = (x >> b) & 1;
            if (t[v][bit] == -1) { t[v][bit] = t.size(); t.push_back({-1,-1}); }
            v = t[v][bit];
        }
    }
    int query_max(int x) {                  // макс XOR x с числом из бора
        int v = 0, res = 0;
        for (int b = B; b >= 0; --b) {
            int bit = (x >> b) & 1;
            int want = bit ^ 1;             // хотим противоположный бит
            if (t[v][want] != -1) { res |= (1 << b); v = t[v][want]; }
            else v = t[v][bit];
        }
        return res;
    }
};

Алгоритм: вставляем все числа, для каждого a[i] спрашиваем query_max(a[i]), берём максимум. Время — O(n · B) = O(n·30), память — O(n·B). Жадность корректна, потому что старший установленный бит результата важнее любого набора младших.

5

Грабли с числом бит: для a[i] < 2^30 хватает B=29..30; для long long до 2^63 берите B=62 и 1LL << b, иначе обрежете старшие биты и получите WA. И аккуратно с (1 << b) при b >= 31 — это UB на int, нужно (1LL << b).

Ваш ответ

Войдите, чтобы ответить на вопрос.