IOI 2024
IOI 2024

Mosaic

Given two arrays X[0..N-1] and Y[0..N-1] (with X[0] = Y[0]), define an N N grid where: Row 0: grid[0][j] = X[j] Column 0: grid[i][0] = Y[i] Otherwise: grid[i][j] = 1 if both grid[i-1][j] = 0 and grid[i][j-1] = 0; else...

Updated May 21, 2026
Track IOI
Year 2024
Statement Rendered from TeX
TeXC++Rendered statement

Problem Statement

Rendered from the "Problem Summary" section in the LaTeX write-up.

Given two arrays $X[0..N-1]$ and $Y[0..N-1]$ (with $X[0] = Y[0]$), define an $N \times N$ grid where:

  • Row 0: $\text{grid}[0][j] = X[j]$

  • Column 0: $\text{grid}[i][0] = Y[i]$

  • Otherwise: $\text{grid}[i][j] = 1$ if both $\text{grid}[i-1][j] = 0$ and $\text{grid}[i][j-1] = 0$; else $\text{grid}[i][j] = 0$.

  • Equivalently, $\text{grid}[i][j] = 1 - (\text{grid}[i-1][j] \text{ OR } \text{grid}[i][j-1]) = (1 - \text{grid}[i-1][j]) \text{ AND } (1 - \text{grid}[i][j-1])$.

    Or: $\text{grid}[i][j] = \text{grid}[i-1][j] \text{ XOR } \text{grid}[i][j-1] \text{ XOR } (\text{grid}[i-1][j] \text{ AND } \text{grid}[i][j-1])$... Actually it's simpler: $\text{grid}[i][j] = 1 \iff \text{grid}[i-1][j] = 0$ and $\text{grid}[i][j-1] = 0$. This is equivalent to NOR.

    After computing the grid, answer $Q$ queries: each query asks for the number of 1-cells in a subrectangle $[T, B] \times [L, R]$.

Editorial

The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.

Solution Approach

Grid Computation

The recurrence $\text{grid}[i][j] = (1 - \text{grid}[i-1][j]) \cdot (1 - \text{grid}[i][j-1])$ can be shown to be equivalent to XOR in many cases. Specifically:

Claim: $\text{grid}[i][j] = X[j] \text{ XOR } Y[i]$ if... no, this doesn't hold in general.

Actually, observe:

  • If we define $G[i][j] = \text{grid}[i][j]$, then $G[i][j] = 1$ iff both $G[i-1][j] = 0$ and $G[i][j-1] = 0$.

  • Equivalently, $G[i][j] = 0$ iff $G[i-1][j] = 1$ or $G[i][j-1] = 1$.

  • So $G[i][j] = 0$ means there exists a 1 on the ``staircase path'' from $(0,j)$ and $(i,0)$ to $(i,j)$.

  • In fact, $G[i][j] = 1$ iff $G[i-1][j] = 0$ and $G[i][j-1] = 0$, which iff there's no 1 in the top-left ``staircase'' from $(i,j)$. More precisely:

    $G[i][j] = 1$ iff $X[j'] = 0$ for all $j' \le j$ and $Y[i'] = 0$ for all $i' \le i$... No, that's also not right.

    Let me just compute it directly: $G[i][j]$ is 1 iff both neighbors (above and left) are 0. We can compute the entire grid in $O(N^2)$.

2D Prefix Sums for Queries

Precompute a 2D prefix sum array $P$ where $P[i][j] = \sum_{r \le i, c \le j} G[r][c]$. Then each query is answered in $O(1)$.

C++ Solution

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<ll> mosaic(vector<int> X, vector<int> Y,
                   vector<int> T, vector<int> B,
                   vector<int> L, vector<int> R) {
    int N = X.size();
    int Q = T.size();

    // Compute grid
    vector<vector<int>> G(N, vector<int>(N));
    for (int j = 0; j < N; j++) G[0][j] = X[j];
    for (int i = 0; i < N; i++) G[i][0] = Y[i];
    for (int i = 1; i < N; i++)
        for (int j = 1; j < N; j++)
            G[i][j] = (G[i-1][j] == 0 && G[i][j-1] == 0) ? 1 : 0;

    // 2D prefix sums
    vector<vector<ll>> P(N + 1, vector<ll>(N + 1, 0));
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            P[i][j] = G[i-1][j-1] + P[i-1][j] + P[i][j-1] - P[i-1][j-1];

    // Answer queries
    vector<ll> ans(Q);
    for (int q = 0; q < Q; q++) {
        int t = T[q], b = B[q], l = L[q], r = R[q];
        ans[q] = P[b+1][r+1] - P[t][r+1] - P[b+1][l] + P[t][l];
    }

    return ans;
}

int main() {
    int N, Q;
    scanf("%d", &N);
    vector<int> X(N), Y(N);
    for (int i = 0; i < N; i++) scanf("%d", &X[i]);
    for (int i = 0; i < N; i++) scanf("%d", &Y[i]);
    scanf("%d", &Q);
    vector<int> T(Q), B(Q), L(Q), R(Q);
    for (int q = 0; q < Q; q++)
        scanf("%d %d %d %d", &T[q], &B[q], &L[q], &R[q]);
    auto ans = mosaic(X, Y, T, B, L, R);
    for (int q = 0; q < Q; q++)
        printf("%lld\n", ans[q]);
    return 0;
}

Complexity Analysis

  • Time complexity: $O(N^2 + Q)$ -- $O(N^2)$ to compute the grid and prefix sums, $O(1)$ per query.

  • Space complexity: $O(N^2)$ for the grid and prefix sums.

  • Note: For very large $N$ (up to $10^6$ or more), the $O(N^2)$ approach is too slow. In that case, we can observe that the grid values depend on the positions of 1s in $X$ and $Y$. Specifically, $G[i][j] = 1$ iff $X[1..j]$ and $Y[1..i]$ are all 0 and $X[0] = Y[0] = 0$. For the constrained subtask where queries are on single rows or have special structure, row-based formulas with binary search can be used.

Code

C++ solution used for this page.

C++

Clean code view with a raw-file link when you want the original source.

Raw file
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

// IOI 2024 - Mosaic
// N x N grid defined by top row X and left column Y (with X[0] == Y[0]).
// Recurrence: G[i][j] = 1 iff G[i-1][j] == 0 AND G[i][j-1] == 0 (NOR).
// Answer Q rectangle-sum queries using 2D prefix sums.
// Time: O(N^2 + Q).

vector<ll> mosaic(vector<int> X, vector<int> Y,
                  vector<int> T, vector<int> B,
                  vector<int> L, vector<int> R) {
    int N = X.size();
    int Q = T.size();

    // Build the grid
    vector<vector<int>> G(N, vector<int>(N));
    for (int j = 0; j < N; j++) G[0][j] = X[j];
    for (int i = 0; i < N; i++) G[i][0] = Y[i];
    for (int i = 1; i < N; i++)
        for (int j = 1; j < N; j++)
            G[i][j] = (G[i - 1][j] == 0 && G[i][j - 1] == 0) ? 1 : 0;

    // 2D prefix sums (1-indexed)
    vector<vector<ll>> P(N + 1, vector<ll>(N + 1, 0));
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            P[i][j] = G[i - 1][j - 1] + P[i - 1][j] + P[i][j - 1] - P[i - 1][j - 1];

    // Answer queries
    vector<ll> ans(Q);
    for (int q = 0; q < Q; q++) {
        int t = T[q], b = B[q], l = L[q], r = R[q];
        ans[q] = P[b + 1][r + 1] - P[t][r + 1] - P[b + 1][l] + P[t][l];
    }

    return ans;
}

int main() {
    int N, Q;
    scanf("%d", &N);
    vector<int> X(N), Y(N);
    for (int i = 0; i < N; i++) scanf("%d", &X[i]);
    for (int i = 0; i < N; i++) scanf("%d", &Y[i]);
    scanf("%d", &Q);
    vector<int> T(Q), B(Q), L(Q), R(Q);
    for (int q = 0; q < Q; q++)
        scanf("%d %d %d %d", &T[q], &B[q], &L[q], &R[q]);
    auto ans = mosaic(X, Y, T, B, L, R);
    for (int q = 0; q < Q; q++)
        printf("%lld\n", ans[q]);
    return 0;
}

Source Files and Assets

Raw files are still available here when you want the original TeX, C++, or statement assets.

Show raw files