문제 링크
https://www.acmicpc.net/problem/19242
풀이
부분행렬의 합을 구하기 위해서 나이브한 방법 대신 A의 누적 합 배열인 S를 만들어 놓으면 $[x_1,y_1]$ ~ $[x_2,y_2]$ 부분행렬의 구간합을 $S[x_2][y_2] - S[x_2][y_1-1] - S[x_1-1][y_2] + S[x_1-1][y_1-1]$라는 식을 이용해 $O(1)$만에 구할 수 있습니다.
$y_1$와 $y_2$를 고정한다면 $x_1≤x_2$인 $x_1$과 $x_2$의 모든 쌍에 대한 구간이 존재합니다. $x_1$과 $x_2$의 모든 쌍을 검사하면 구간합이 $X$이하인 부분행렬의 갯수를 찾을 수 있겠지만 검사하기 위해서는 $O(N^2)$이라는 시간이 소요됩니다. $S[x_2][y_2]$ $-S[x_2][y_1-1]$ $-S[x_1-1][y_2]$ $+S[x_1-1][y_1-1]$ $≤$ $X$에서 $x_2$와 관련된 식을 넘긴다면 $-S[x_1-1][y_2]$ $+S[x_1-1][y_1-1]$ $≤$ $X-S[x_2][y_2]$ $+S[x_2][y_1-1]$로 $x_1$과 $x_2$를 분리해서 생각할 수 있습니다. $x_1 ≤ x_2$인 모든 $x_1$의 $-S[x_1-1][y_2]$ $+S[x_1-1][y_1-1]$을 저장하면서 저장한 값들 중에서 $X$ $-S[x_2][y_2]$ $+S[x_2][y_1-1]$이하인 것의 개수를 빠르게 구할 수 있으면 시간을 줄일 수 있습니다. $x_2$를 $1$부터 $N$까지 보면서 $K$이하인 것의 개수를 찾은 다음 $-S[x_2-1][y_2]$ $+S[x_2-1][y_1-1]$를 저장한다면 다음 연산에 사용할 수 있어 다시 볼 필요가 없습니다. 저장 연산을 $O(\log N)$, $K$이하인 값을 찾는데 $O(\log N)$인 자료형을 이용해 구현한다면 $O(M^2N \log N)$이라는 시간 복잡도를 가지게 됩니다.
두 연산을 지원하는 pbds를 이용한다면 상수차이로 시간초과가 나기 때문에 상수가 적은 좌표 압축 + 윅 트리를 이용해 구현해야 합니다. 만약 $X$ $-S[x_2][y_2]$ $+S[x_2][y_1-1]$도 좌표압축에 넣는다면 시간초과가 나기 때문에 $-S[x_1-1][y_2]$ $+S[x_1-1][y_1-1]$만 넣어서 좌표압축을 해야합니다.
전체 코드
1 |
|