Homochromatic square perimeters

December 3, 2021

Cells in an NN-by-NN grid GG are colored in monochrome:

 0i,j<N,let Gi,j={0white1black.\forall~0\leq i,j<N,\text{let}~G_{i,j}=\begin{cases} 0&\text{white}\\ 1&\text{black} \end{cases}.

Find the smallest non-negative integer KK, such that there exists no square of cells in GG, with side length K>KK'>K, whose perimeter consists entirely of black cells.

Codeforces/Polygon practice problem.

O(N3)O(N^3) via pre-computation

The problem reduces to finding the side length of the largest square whose perimeter is entirely black, or 00 if no black cells exist. We denote such squares valid. Let Li,jL_{i,j} store the largest length of consecutive black cells, starting from cell i,ji,j and moving left. For white cell Gi,j=0G_{i,j}=0, let Ri,j=0R_{i,j}=0. Similarly, define Ui,jU_{i,j} for moving upwards. The O(N2)O(N^2) indices for L,UL,U may be computed in O(1)O(1) each with the recurrence

Li,j={Gi,jj=00Gi,j=0Li,j1+1Gi,j=1L_{i,j}=\begin{cases} G_{i,j}&j=0\\ 0&G_{i,j}=0\\ L_{i,j-1}+1&G_{i,j}=1 \end{cases}

and similarly for UU.

Each square in GG may be specified by a tuple (i,j,k)(i,j,k) of upper-left corner i,ji,j and side length kk. The square Qi,j,kQ_{i,j,k} is valid if and only if all four edges are entirely black; that is, all four conditions below are satisfied:

{Li,j+k1ktop edgeUi+k1,j+k1kright edgeLi+k1,j+k1kbottom edgeUi+k1,jkleft edge\begin{cases} L_{i,j+k-1}\geq k&\text{top edge}\\ U_{i+k-1,j+k-1}\geq k&\text{right edge}\\ L_{i+k-1,j+k-1}\geq k&\text{bottom edge}\\ U_{i+k-1,j}\geq k&\text{left edge} \end{cases}

For each of the O(N3)O(N^3) squares, this check for validity costs O(1)O(1).

O(N3)O(N^3) C++ code.

O(N2α(N))O(N^2\alpha(N)) amortized via radix sort and DSU/Union-Find

First, compute L,UL',U', similarly to L,UL,U, but for lengths of black cells moving right, and downwards, respectively.

Each of the O(N)O(N) upper-left-to-bottom-right diagonals may be specified by (i,j)(i,j) as the diagonal which passes through cell i,ji,j. Denote the diagonals by DD. Note that Di,jD_{i,j} specifies the same diagonal as Di+1,j+1D_{i+1,j+1}.

For a given upper-left corner i,ji,j, we check all squares Qi,j,kQ_{i,j,k} for validity by querying a DSU for the maximum valid kk for that i,ji,j. To begin, define the reach RR over the diagonal:

Ri,j=min(Ui,j,Li,j)R_{i,j}=\min(U_{i,j},L_{i,j})

and reverse reach RR':

Ri,j=min(Ui,j,Li,j).R'_{i,j}=\min(U'_{i,j},L'_{i,j}).

Intuitively, the reach RR specifies the maximum side length for a valid square with bottom-right corner i,ji,j, while the reverse reach RR' specifies similarly for the upper-left corner i,ji,j. In other words, square Qi,j,kQ_{i,j,k} is valid if and only if both conditions below are satisfied:

{Ri,jkRi+k1,j+k1k.(1.1, 1.2)\begin{cases} R'_{i,j}\geq k\\ R_{i+k-1,j+k-1}\geq k \end{cases}.\tag{1.1, 1.2}

We can remove condition (1.2)(1.2)’s dependence on kk by defining the discounted reach RR'':

Ri,j=Ri,ji.R''_{i,j}=R_{i,j}-i.

(1.1,1.2)(1.1, 1.2) may now be rewritten:

{kRi,jRi+k1,j+k11i.(2.1, 2.2)\begin{cases} k\leq R'_{i,j}\\ R''_{i+k-1,j+k-1}\geq 1-i \end{cases}.\tag{2.1, 2.2}

We process the upper-left corners i,ji,j along diagonal Di,jD_{i,j} in increasing order of ii, 1i1-i decreases. Thus, the set SS of indices (i,j)=(i+k1,j+k1)(i',j')=(i+k-1,j+k-1) which satisfy (2.2)(2.2) never shrinks. More specifically, at i,ji,j, all bottom-right corners (i,j)(i',j') with Ri,j1iR''_{i',j'}\geq 1-i must be added to SS. As we have already processed (i1,j1)(i-1,j-1) at this point, only the bottom-right corners which satisfy Ri,j=1i+1R''_{i',j'}=1-i+1 need to be added. We may query for these (i,j)(i',j') in O(1)O(1) by pre-sorting in O(N)O(N), with radix sort, all the Ri,jR''_{i',j'} on the diagonal.

At a given upper-left corner i,ji,j, then, the maximal valid bottom-right corner is the maximal (i,j)S(i',j')\in S which also satisfies (2.1)(2.1):

k=ii+1Ri,j    iRi,j+i1.(3)k=i'-i+1\leq R'_{i,j}\implies i'\leq R'_{i,j}+i-1.\tag{3}

Formally, we wish to make two types of queries to set SS:

  1. Add(i,j)Add(i,j): Add (i,j)(i,j) to the set.
  2. Get(i)Get(i'): Query the largest (i,j)(i,j) in the set with iii\leq i'.

Observe that for some i,ji,j, if (i,j)S(i,j)\notin S, then Get(i)=Get(i1)Get(i)=Get(i-1). This leads us to consider implementing SS with a DSU. Should we process upper-left corners in decreasing order of ii instead of increasing order, 1i1-i increases, and SS never grows. Thus, instead of AddAdd, we wish to support RemoveRemove.

Before moving on to the reduction to DSU, we first discuss an example.

Take, for example, the following input GG with K=4K=4 from the square with upper-left corner at (1,1)(1, 1):

110111
011110
010011
111011
111111
111111

Consider the processing of the major diagonal D0,0D_{0, 0}. As mentioned, we step through the diagonal in decreasing order of ii.

ii jj RR RR' RR'' R+i1R'+i-1 1i1-i
55 55 44 11 1-1 55 4-4
44 44 55 22 11 55 3-3
33 33 00 00 3-3 22 2-2
22 22 00 00 2-2 11 1-1
11 11 11 44 00 44 00
00 00 11 11 11 00 11

Observe, as noted previously, that R+i1R'+i-1 intuitively calculates the maximum row index which may serve as a bottom-right corner for a given upper-left corner i,ji,j. In addition, for any upper-left corner i,ji,j, it may form a valid square with bottom-right corner i,ji',j' as long as Ri,j1iR''_{i',j'}\geq 1-i and Ri,j+i1iR'_{i,j}+i-1\geq i'. These together describe conditions (2.2)(2.2) and (3)(3), respectively.

To visualize the operations on SS, we arrange it onto a line with corner (0,0)(0,0) on the left and (5,5)(5,5) on the right. Initially, all corners are part of SS:

||||||
012345

At any point in time, we either remove an element from SS, or we stand at some point on the line, and look left to identify the index of the first | blocking our view. Since SS is unchanged prior to visiting (3,3)(3,3), we take that as our first example. As 1i1-i is 2-2, we must remove all (i,j)(i',j') from SS where Ri,jR''_{i',j'} is smaller than 2-2. Thus, we remove (3,3)(3,3) from SS:

|||_||
012345

Intuitively, (3,3)(3,3) has been removed from consideration as a bottom-right corner. This is because any bottom or right edges which extend from it can no longer reach any upper-left corners we have yet to process, or the upper-left corner we are currently processing: (3,3)(3,3).

We wrap up processing upper-left corner (3,3)(3,3) by querying SS for the maximal bottom-right corner with iR3,3+31=2i'\leq R'_{3,3}+3-1=2, which is the bottom-right corner (2,2)(2,2). To visualize this, imagine standing at index 22 on the SS line and looking left for the first | blocking your vision (index 22 counts). This is the | at 22, which represents bottom-right corner (2,2)(2,2).

|||_||
012345
  ^

This means that the maximal valid square with upper-left corner at (3,3)(3,3) has bottom-right corner at (2,2)(2,2), which is not a valid square at all. This is expected, since there is no valid square with upper-left corner at (3,3)(3,3), as the cell is colored white.

In the next step, we process upper-left corner (2,2)(2,2). Noting first that its 1i1-i is 1-1, we must remove all indices (i,j)(i',j') from SS which have Ri,j<1R''_{i',j'}<-1. Once again, that bottom-right corner is (2,2)(2,2):

||__||
012345
 ^

and when we eventually query, we will stand at index R2,2+21=1R'_{2,2}+2-1=1 and look left, to which we see the bottom-right corner (1,1)(1,1). This once again means that no valid square exists with upper-left corner (2,2)(2,2).

In the next step, we process upper-left corner (1,1)(1,1). We have its 1i=01-i=0, we we will remove from SS the indices where Ri,j=1R''_{i',j'}=-1 now. This turns out to be bottom-right corner (5,5)(5,5):

||__|_
012345

Now, we stand at index R1,1+11=4R'_{1,1}+1-1=4 and look left:

||__|_
012345
    ^

Luckily, we see the bottom-right corner (4,4)(4,4), which means that, as expected, the maximal valid square with upper-left corner at (1,1)(1,1) has side length 41+1=44-1+1=4. We must now update our answer if necessary.

In the final step, we process upper-left corner (0,0)(0,0). 1i=11-i=1, so we remove any indices where R=0R''=0. The only such index in SS is (1,1)(1,1):

|___|_
012345

Standing at index R+01=0R'+0-1=0 and looking left, we see (0,0)(0,0), which means that the maximal valid square starting at (0,0)(0,0) has side length 11.

We reduce SS into a DSU SS' by implementing it together with array SS'', both over indices (i,j)(i,j) on Di,jD_{i,j}. Intuitively, SS' stores which $Get$s return the same answer, and SS'' stores that answer. Initialize each (i,j)(i,j) of SS' as disjoint, and each Si,j=(i,j)S''_{i,j}=(i,j).

  1. Remove(i,j)Remove(i,j): Now, Get(i)Get(i) must give the same answer as g=Get(i1)g=Get(i-1), so update SS' with Union((i,j),(i1,j1))Union((i,j), (i-1,j-1)). Then update SS'':

    SFind(i,j)=g.S''_{Find(i,j)}=g.

  2. Get(i)Get(i'): Return SFind(i,j)S''_{Find(i',j')} for the jj' on the diagonal.

For each of the O(N)O(N) diagonals, SS contains O(N)O(N) elements and is queried O(N)O(N) times. These queries are bottlednecked by the SS' DSU implementation, costing O(Nα(N))O(N\alpha(N)) per diagonal. For the implementation, care must be taken with Remove(i,j)Remove(i,j) for the smallest ii in a diagonal.

O(N2α(N))O(N^2\alpha(N)) C++ code.