[ 백준 ] 6198 / 옥상 정원 꾸미기

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
60/228
post-thumbnail

# Appreciation

/*
 * Problem :: 6198 / 옥상 정원 꾸미기
 *
 * Kind :: Data Structure
 *
 * Insight
 * - 자신(관리인)이 위치한 빌딩보다 높거나 같은 빌딩이 있으면
 *   그 다음에 있는 모든 빌딩의 옥상은 보지 못한다
 *   + 자신보다 높거나 같은 빌딩을 만나면
 *     그 뒤의 빌딩의 옥상들은 볼 수가 없으므로
 *     그 때, 자신이 볼 수 있는 빌딩의 옥상 개수가 정해지게 된다
 *
 * - N=6, H={10, 3, 7, 4, 12, 2}
 *   + 10 / [1]
 *     10 3 / [1] [2]
 *     10 3 7 / [1] [2] [3]
 *     # H[2] < H[3] 이므로 2번 관리인은 3번 빌딩부터 모든 빌딩을 볼 수 없다
 *     10 7 4 / [1] [3] [4]
 *     10 7 4 12 / [1] [3] [4] [5]
 *     # H[4] < H[5] 이므로 4번 관리인은 5번 빌딩부터 모든 빌딩을 볼 수 없다
 *     # H[3] < H[5] 이므로 3번 관리인은 5번 빌딩부터 모든 빌딩을 볼 수 없다
 *       3번 빌딩은 4번 빌딩을 볼 수 있다
 *     # H[1] < H[5] 이므로 1번 관리인은 5번 빌딩부터 모든 빌딩을 볼 수 없다
 *       1번 빌딩은 3번, 4번 빌딩을 볼 수 있다
 *       -> 4번 빌딩은 1번, 3번 관리인에게 옥상이 보여진다
 *          3번 빌딩은 1번 관리인에게 옥상이 보여진다
 *          => 10 7 4 / n({10, 7}) = 2
 *             10 7 / n({10}) = 1
 *             10 / n({}) = 0
 *     12 2 / [5] [6]
 *     # 6번 관리인은 마지막 빌딩으로 볼 수 있는 빌딩이 없다
 *     # H[5] > H[6] 이므로 5번 관리인은 6번 빌딩을 볼 수 있다
 *       -> 자신보다 높은 빌딩을 만날 때마다 볼 수 있는 옥상의 개수가 계산된 후
 *          순열에서 제거되므로, 맨 마지막에 남은 순열은 내림차순이 될 수 밖에 없다!
 *          => 5 4 3 2 1 / [5] [4] [3] [2] [1] 이 남은 순열이라면
 *             2번 관리인은 1번
 *             3번 관리인은 2번, 1번
 *             4번 관리인은 3번, 2번, 1번
 *             5번 관리인은 4번, 3번, 2번, 1번
 *             을 볼 수 있다!
 *
 * - 순열에서 가장 최근에 삽입된 원소를 쉽게 알 수 있어야 한다
 *   순열에서 가장 최근에 삽입된 원소를 제거할 수 있어야 한다
 *   순열의 크기를 항상 알 수 있어야 한다
 *   + Stack 이다!
 *
 * Point
 * - 편의상 빌딩의 번호는 0 부터 시작하는 것으로 생각했다
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <stack>

using namespace std;

#define endl '\n'

// Set up : Global Variables
/* None */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    int N; cin >> N;
    int H[N];
    for (int i=0; i<N; i++)
        cin >> H[i];

    // Process
    stack<int> st; /* 빌딩의 번호가 원소로 삽입됨 */

    long ans = 0;
    for (int i=0; i<N; i++) {
        /* top = Stack 에서 가장 최근에 삽입된 빌딩의 번호
         * i = 현재 빌딩의 번호
         * H[top] = 가장 최근에 삽입된 빌딩의 높이
         * H[i] = 현재 빌딩의 높이
         * size = 현재 Stack 의 크기 (Stack 에 있는 빌딩의 개수) */

        /* H[i] >= H[top] 이면
         * Stack 에서 높이가 H[i] 이하인 빌딩들의 관리인이
         * 볼 수 있는 다른 빌딩의 옥상의 개수를 계산 */
        while (not(st.empty()) && H[i] >= H[st.top()]) {
            ans += st.size()-1; /* top 은 왼쪽의 size-1 개의 빌딩에 옥상이 보여짐 */
            st.pop(); /* top 제거 */
        } st.push(i); /* i 추가 */
    }

    while (not(st.empty())) {
        ans += st.size()-1; /* top 은 왼쪽의 size-1 개의 빌딩에 옥상이 보여짐 */
        st.pop(); /* top 제거 */
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글