2차원 배열 \(A\)가 주어질 때, \(y_1 \le y \le y_2\), \(x_1 \le x \le x_2\) 를 만족하는 \(A[y][x]\)로 구성된 \(A\)의 부분직사각형 \((y_1, y_2, x_1, x_2)\)에 대하여 다음을 만족하는 부분직사각형의 개수를 구하여라.
\(N \le 3\)이니, \(1\)차원 배열에서 \(x\)축에 대하여 다음 조건을 만족하는 구간 \((x_1, x_2)\)의 개수를 세는 문제이다.
\(2 \le x_1 \le x_2 \le M-1\)
\(\forall x_1 \le x \le x_2\), \(min(A[2][x_1-1], A[2][x_2+1])>A[2][x]\)
\(\forall x_1 \le x \le x_2\), \(min(A[1][x], A[3][x])>A[2][x]\)
조건 \(min(A[1][x], A[3][x])>A[2][x]\)을 만족하지 않는 점 \(x\)는 어떤 구간에도 포함될 수 없으니, 조건을 만족하는 점들만 남기고 배열을 여러 개의 배열로 쪼갤 수 있다.
이와 같이 배열을 쪼갠 후 조건 \(min(A[2][x_1-1], A[2][x_2+1])>A[2][x]\)을 만족하는 구간의 개수를 세자.
구간의 최댓값 \(A[k]\)를 고정해 놓고, \(A[k]\)를 포함하며 조건을 만족하는 구간 \((l, r)\)이 몇개 있을 수 있는지 생각해보자.
\(A[k]\)가 최댓값이기 때문에 \(A[l-1]>A[k]\), \(A[r+1]>A[k]\), \(A[i] \le A[k] (l \le i \le r)\)를 만족해야 한다.
\(l=r=k\)에서 시작하여, 조건을 만족할 때까지 한 칸씩 확장시켜보자. \(A[l-1] \le A[k]\)이거나 \(A[r+1] \le A[k]\)라면, 조건을 만족하지 않기 때문에 \(l\)이나 \(r\)을 한 칸씩 확장시켜 구간 안에 포함시켜야 한다.
위 과정을 반복하여 \(A[l] > A[k]\), \(A[r] > A[k]\)라면, 조건을 만족할 뿐만 아니라 여기서 한칸이라도 더 확장시키는 순간 \(A[k]\)가 최댓값이라는 조건에 위배되니, 이러한 \((l, r)\)이 조건을 만족하는 유일한 \((l, r)\)이다.
따라서, 각 최댓값 \(A[k]\)에 대하여 조건을 만족하는 \((l, r)\)은 최대 \(1\)개 존재하니, 전체 가능한 답의 개수는 최대 \(O(M)\)이다.
각 \(k\)에 대하여 \(l<k, A[l]>A[k]\)인 최대 \(l\)와 \(k<r, A[r]>A[k]\)인 최대 \(r\)을 stack으로 관리하면 \(O(M)\)에 해결할 수 있다.
Observation 1
\(1\)차원 문제에서 구간의 최댓값을 \(A[k]\)로 고정하였을 때 조건 \(\forall x_1 \le x \le x_2\), \(min(A[2][x_1-1], A[2][x_2+1])>A[2][x]\)을 만족하는 \((x_1, x_2)\)은 최대 \(1\)개 존재한다.
따라서 전체 가능한 구간의 수는 최대 \(O(M)\)개이다.
CheckPoint
Observation 1에 의해 1차원 문제에서 가능한 구간의 수는 최대 \(N\)개이니 각 \(k\)에 대하여 \(l<k, A[l]>A[k]\)인 최대 \(l\)와 \(k<r, A[r]>A[k]\)인 최소 \(r\)을 stack으로 관리하면 \(O(M)\)에 해결할 수 있다.
\(2\)차원 상황에서도 비슷한 아이디어로 접근할 수 있다.
우선, Observation 1에서 조건 \(\forall \ y_1 \le y \le y_2, x_1 \le x \le x_2\), \(min(A[y_1-1][x], A[y_2+1][x])>A[y][x], min(A[y][x_1-1], A[y][x_2+1])>A[y][x]\)을 만족하는 "구간" \((y_1, y_2)\), \((x_1, x_2)\)는 각 행, 열별로 \(O(M)\), \(O(N)\)개이다.
또한, 전과 비슷하게 직사각형 내의 전체 최댓값 \(A[p][q]\)를 고정하면 Observation 1에서 \(p\)행과 \(q\)열에 대하여 조건을 만족하는 \((y_1, y_2, x_1, x_2)\)는 정확히 \(1\)개이다.
따라서 전체 가능한 답의 최대 개수 또한 \(O(NM)\)임을 알 수 있다.
Observation 2
직사각형의 최댓값을 \(A[p][q]\)로 고정하였을 때 조건을 만족하는 직사각형 \((y_1, y_2, x_1, x_2)\)은 Observation 1에 의해 정확히 하나로 결정된다.
따라서 전체 가능한 직사각형의 수는 최대 \(O(NM)\)개이다.
이제 위 \(O(NM)\)개의 직사각형 후보들을 구하고, 각 후보에 대하여 직사각형 내의 다른 값들에 대해서도 조건이 성립하는지만 빠르게 확인해주면 된다.
우선, 직사각형 후보를 구하는 것은 각 행과 열에 대한 \(1\)차원 문제로 생각하고 Subtask 5에서 구했던 것과 같은 방법으로 stack을 이용하여 각 행, 열별로 조건을 만족하는 구간들을 구하면 된다.
각 행, 열별로 \(O(M)\), \(O(N)\)의 시간이 걸리니 전체 \(O(NM)\)의 시간에 해결할 수 있다.
직사각형 후보 \((y_1, y_2, x_1, x_2)\)가 조건을 성립하는지 확인하는 방법은, \(\forall \ y_1 \le y \le y_2\), 행 \(y\)에 대한 구간 \((y, x_1, x_2)\)이 조건을 만족하며 \(\forall \ x_1 \le x \le x_2\), 열 \(x\)에 대한 구간 \((x, y_1, y_2)\)이 조건을 만족하는지 확인하는 것이다.
이를 위하여 다음과 같은 값을 전처리하자.
Definition 1
\(low(y_1, x_1, x_2):=\) 행 \(y_1\)에 대한 구간 \((y_1, x_1, x_2)\)이 조건을 만족할 때, 조건을 만족하며 내려갈 수 있는 최대의 \(y\) \(low(y_1, x_1, x_2)=y_2\)라 할 때, \(\forall \ y_1 \le y \le y_2\), 행 \(y\)에 대한 구간 \((y, x_1, x_2)\)이 모두 조건을 만족하는 최대의 \(y_2\)
\(low(x_1, y_1, y_2):=\) 열 \(x_1\)에 대한 구간 \((x_1, y_1, y_2)\)이 조건을 만족할 때, 조건을 만족하며 오른쪽으로 갈 수 있는 최대의 \(x\) \(low(x_1, y_1, y_2)=x_2\)라 할 때, \(\forall \ x_1 \le x \le x_2\), 열 \(x\)에 대한 구간 \((x, y_1, y_2)\)이 모두 조건을 만족하는 최대의 \(x_2\)
조건을 만족하는 행 \(y\)에 대한 구간 \((y, x_1, x_2)\), 열 \(x\)에 대한 구간 \((x, y_1, y_2)\)을 모두 구해놓았다면 \(low(y_1, x_1, x_2)\), \(low(x_1, y_1, y_2)\) 또한 구할 수 있다.
조건을 만족하는 \(NM\)개의 일차원 구간들을 모두 \(y\), \(x\)에 대하여 정렬한 후, 다음 \(y\), \(x\)에 대한 구간이 존재하는지 확인하면 되기 때문에, 이분탐색 등을 통해 이 과정은 \(O(NM\log NM)\)에 전처리 하면 된다.
이제, 직사각형 후보 \((y_1, y_2, x_1, x_2)\)가 조건을 성립하는지 확인하는 방법은 단순히 \(low(y_1, x_1, x_2) \ge y_2\), \(low(x_1, y_1, y_2) \ge x_2\)인지 확인하는 것이다.
CheckPoint
Observation 2에 의해 전체 가능한 직사각형 후보의 수가 \(O(NM)\)개이니, Subtask 5에서 구했던 것과 같은 방법으로 stack을 이용하여 각 행, 열별로 조건을 만족하는 구간들을 \(O(NM)\)에 구한다.
직사각형 후보가 조건을 만족하는지 확인하기 위하여 Definition 1과 같이 \(low(y_1, x_1, x_2)\), \(low(x_1, y_1, y_2)\)를 이분탐색 등을 활용하여 \(O(NM\log NM)\)에 전처리한다.
이후, 직사각형 후보 \((y_1, y_2, x_1, x_2)\)가 조건을 성립하는지 확인하기 위하여 \(low(y_1, x_1, x_2) \ge y_2\), \(low(x_1, y_1, y_2) \ge x_2\)인지 확인하여 답의 개수를 센다.
Complexity
Time Complexity : \(O(NM\log NM)\)
하지만 이를 그냥 구현하면 TLE를 받고, vector을 이용하지 말고, 이분탐색보다는 Two Pointer 이 가능한 경우에는 Two Pointer을 이용하고, 비트별로 쪼개는 등의 여러 최적화를 해야 100점을 맞을 수 있다.