Official

G - Domino Covering XOR Editorial by en_translator


Let \(f(n)\) be the number of ways to place dominoes on a (not necessarily rectangular) grid with a total of \(n\) cells. How does \(f(n)\) grow?

Among the \(n\) cells, take a cell that does not have a cell above nor to is left. Then this cell satisfies exactly one of these:

  • This cell is not covered by a domino.
  • This cell is covered by a vertical domino.
  • This cell is covered by a horizontal domino.

For each of them, there are at most \(f(n-1),f(n-2),f(n-2)\) ways to place dominoes.

Therefore, we have \[f(n)\leq f(n-1)+2f(n-2)\]. Since \(f(1)=1,f(0)=1\), we obtain \(f(n)\leq\dfrac{2 ^ {n+1}+(-1) ^ n}3\).

Therefore, we see that inspecting all placements of dominoes exhaustively is fast enough. The implementation can be simplified by managing the cells already occupied by a domino as an \(HW\)-bit bitmask integer.

The following is sample code. The time complexity is \(O(HW2 ^ {HW})\). Right after line \(30\), we may eliminate duplicates to reduce the number of states to manage, but note that this process may worsen the computational complexity.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    using namespace std;
    unsigned H, W;
    cin >> H >> W;
    vector A(H, vector<unsigned long>(W));
    for (auto&& row : A)
        for (auto&& a : row)
            cin >> a;

    // Use an (HW)-bit integer to manage the cells occupied by dominoes
    vector<unsigned> possible_domino{0}; // Initially, there is an empty grid

    const unsigned domino_vertical = (1U << W) + 1, domino_horizontal = 3;

    for (unsigned i = 0, bit = 0; i < H; ++i)
        for (unsigned j = 0; j < W; ++j, ++bit) { // For each cell
            vector<unsigned> tmp;
            for (const auto b : possible_domino) {
                // If a horizontal domino can be placed, add such a placement
                if (j + 1 < W && !(b & domino_horizontal << bit))
                    tmp.emplace_back(b | domino_horizontal << bit);
                // If a vertical domino can be placed, add such a placement
                if (i + 1 < H && !(b & domino_vertical << bit))
                    tmp.emplace_back(b | domino_vertical << bit);
            }
            ranges::move(tmp, back_inserter(possible_domino));
        }

    unsigned long ans = 0;
    for (const auto b : possible_domino) { // For each placement
        unsigned long now = 0;
        for (unsigned i = 0, bit = 0; i < H; ++i)
            for (unsigned j = 0; j < W; ++j, ++bit)
                if (1 & ~b >> bit) // inspect each cell not covered by a domino
                    now ^= A[i][j]; // to find the total XOR
        ans = max(ans, now); // Update if it is larger
    }

    cout << ans << endl;
    return 0;
}

posted:
last update: