※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 2874번 문제인 검정 직사각형이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/2874

 

격자 위에서의 두 겹치지 않는 직사각형은 (1)어떤 행방향 경계선을 기준으로 두 직사각형이 서로 다른 쪽에 존재하거나 (2)어떤 열방향 경계선을 기준으로 두 직사각형이 서로 다른 쪽에 존재한다. (물론 둘 모두에 해당할 수도 있다.) 따라서 문제의 답은 행방향 경계선으로 나누어 두 직사각형을 넣는 경우의 수와 열방향 경계선을 기준으로 나누어 두 직사각형을 넣는 경우의 수의 합에서 두 경계선 모두로 나누어 직사각형을 넣는 경우의 수를 빼는 것으로 구할 수 있다.

 

위 각각의 경우의 수는 각 칸을 기준으로 해당 칸을 좌상단, 좌하단, 우상단, 우하단 칸으로 갖는 경우의 수 및 그 값들의 적절한 2차원 누적합을 전처리한 후 스위핑하는 것으로 빠르게 계산할 수 있다. 글쓴이는 각 경우의 수를 스택을 이용한 히스토그램 문제 풀이법을 이용해 계산하였다. (이 문제에 히스토그램이 어디에 있는지 모르겠다면, 각 행을 기준으로 그 행의 밑바닥(?)에 붙어있는 위쪽 열방향으로 연속한 검정 칸모양을 그려보면 히스토그램과 같음을 알 수 있을 것이다. 이 아이디어는 의외로 곳곳에서 활용되므로 기억해두는 것이 좋다.)

 

10007로 나눈 나머지를 구하라는 조건을 놓쳐 몇 번 틀렸다(...). 항상 문제가 요구하는 것을 주의깊게 읽자.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

int N;
char board[1002][1002];
int LU[1002][1002], RU[1002][1002], LD[1002][1002], RD[1002][1002];
int H[1002];

vector<pair<int, int>> stk; // {높이, 길이}
int ans;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> N; stk.reserve(N);
	for (int r = 1; r <= N; r++) {
		for (int c = 1; c <= N; c++) {
			cin >> board[r][c];
		}
	}
	
	memset(H, 0, sizeof(H));
	for (int r = 1; r <= N; r++) {
		int psum = 0;
		stk.clear();
		for (int c = 1; c <= N; c++) {
			int &h = H[c];
			if (board[r][c] == 'C') h++;
			else h = 0;
			int len = 1;
			while (!stk.empty() && stk.back().first >= h) {
				len += stk.back().second;
				psum -= stk.back().first * stk.back().second;
				stk.pop_back();
			}
			psum += h * len;
			stk.emplace_back(make_pair(h, len));
			LU[r][c] = (max(psum - 1, 0) + LU[r - 1][c] + LU[r][c - 1] - LU[r - 1][c - 1]) % 10007;
		}
	}

	memset(H, 0, sizeof(H));
	for (int r = 1; r <= N; r++) {
		int psum = 0;
		stk.clear();
		for (int c = N; c > 0; c--) {
			int &h = H[c];
			if (board[r][c] == 'C') h++;
			else h = 0;
			int len = 1;
			while (!stk.empty() && stk.back().first >= h) {
				len += stk.back().second;
				psum -= stk.back().first * stk.back().second;
				stk.pop_back();
			}
			psum += h * len;
			stk.emplace_back(make_pair(h, len));
			RU[r][c] = (max(psum - 1, 0) + RU[r - 1][c] + RU[r][c + 1] - RU[r - 1][c + 1]) % 10007;
		}
	}

	memset(H, 0, sizeof(H));
	for (int r = N; r > 0; r--) {
		int psum = 0;
		stk.clear();
		for (int c = N; c > 0; c--) {
			int &h = H[c];
			if (board[r][c] == 'C') h++;
			else h = 0;
			int len = 1;
			while (!stk.empty() && stk.back().first >= h) {
				len += stk.back().second;
				psum -= stk.back().first * stk.back().second;
				stk.pop_back();
			}
			psum += h * len;
			stk.emplace_back(make_pair(h, len));
			RD[r][c] = (max(psum - 1, 0) + RD[r + 1][c] + RD[r][c + 1] - RD[r + 1][c + 1]) % 10007;
		}
	}

	memset(H, 0, sizeof(H));
	for (int r = N; r > 0; r--) {
		int psum = 0;
		stk.clear();
		for (int c = 1; c <= N; c++) {
			int &h = H[c];
			if (board[r][c] == 'C') h++;
			else h = 0;
			int len = 1;
			while (!stk.empty() && stk.back().first >= h) {
				len += stk.back().second;
				psum -= stk.back().first * stk.back().second;
				stk.pop_back();
			}
			psum += h * len;
			stk.emplace_back(make_pair(h, len));
			LD[r][c] = (max(psum - 1, 0) + LD[r + 1][c] + LD[r][c - 1] - LD[r + 1][c - 1]) % 10007;
		}
	}

	for (int r = 1; r < N; r++) {
		ans += (RU[r][1] - RU[r - 1][1]) * RD[r + 1][1];
		ans %= 10007;
	}
	for (int c = 1; c < N; c++) {
		ans += (LD[1][c] - LD[1][c - 1]) * RD[1][c + 1];
		ans %= 10007;
	}
	for (int r = 1; r <= N; r++) {
		for (int c = 1; c <= N; c++) {
			ans -= (LU[r][c] - LU[r - 1][c] - LU[r][c - 1] + LU[r - 1][c - 1]) * RD[r + 1][c + 1];
			ans -= (LD[r][c] - LD[r + 1][c] - LD[r][c - 1] + LD[r + 1][c - 1]) * RU[r - 1][c + 1];
			ans %= 10007;
		}
	}
	ans %= 10007;
	if (ans < 0) ans += 10007;
	cout << ans;
}

 

#랜덤 마라톤 · 코스 9 H번

728x90

'BOJ' 카테고리의 다른 글

[BOJ 20914 // C++] QWERTY 자판  (0) 2024.08.03
[BOJ 22288 // C++] Rainbow Road Race  (0) 2024.08.02
[BOJ 14953 // C++] Game Map  (0) 2024.07.31
[BOJ 25328 // C++] 문자열 집합 조합하기  (0) 2024.07.30
[BOJ 19358 // C++] Waiter's Problem  (0) 2024.07.29

+ Recent posts