[ 백준 ] 15961 / 회전 초밥

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
54/228
post-thumbnail

# Appreciation

/*
 * Problem :: 15961 / 회전 초밥
 *
 * Kind :: Sliding Window
 *
 * Insight
 * - |-----------| / N
 *   |---| / 1~k
 *    |---| / 2~(k+1)
 *     |---| / 3~(k+2)
 *      ...
 *           |---|
 *   |        |---
 *   -|        |--
 *   --|        |-
 *   + max(N)=3*10^6 이니
 *     각 구간에서 서로 다른 초밥의 종류를
 *     쉽고 빠르게 계산할 수 있어야 한다!
 *     # 첫 구간만 계산을 해주고
 *       다음 구간부터는 처음과 끝 초밥만 갱신시켜주면 된다
 *        123456
 *       |-----| / 12345
 *        |-----| / 23456
 *       1번 초밥을 빼주고 6번 초밥을 넣어주자
 *       -> 자료구조 Map 을 사용해서 서로 다른 초밥을 계산해주자
 *          M[i]++
 *          M[j]--, M[j] == 0 이면 M.erase(j)
 *          => 근데 시간초과네...?
 *       -> 자료구조 Map, Set 을 사용해서 서로 다른 초밥을 계산해주자
 *          M[i]++, M[i] == 1 이면 S.insert(i)
 *          M[j]--, M[j] == 0 이면 M.erase(j)
 *          => 통과는 하는데 다른 사람들보다 많이 느린데?
 *       -> 그러고빈, 굳이 초밥의 종류까지는 알 필요는 없다!
 *          또 최대 초밥의 종류(d)의 개수가 최대 초밥의 개수(N)보다 훨씬 작다!
 *          배열(C)로 각 구간에서 초밥의 개수를 계산할 수 있으면 충분하다!
 *          이전 구간에서 서로 다른 초밥의 종류의 개수 = cnt
 *          C[i]++, C[i] == 1 이면 cnt--
 *          C[j]--, C[j] == 0 이면 cnt++
 *
 * Point
 * - Map 이 은근히 시간이 많이 걸리는 자료구조 더라...
 *   + 역시 시간단축엔 배열만 한게 없구나
 */

# Code

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

#include <iostream>
#include <cstring>

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, d, k, c;
    cin >> N >> d >> k >> c;
    int A[N];
    for (int i=0; i<N; i++)
        cin >> A[i];

    // Process
    int C[d+1]; /* 각 초밥 종류에 따른 개수 */
    memset(C, 0, sizeof(C));

    int ans = 0, cnt = 0; /* 현재 구간에서 서로 다른 초밥 종류의 개수 */
    /* 첫 구간 초기화 */
    for (int i=0; i<k; i++) {
        C[A[i]]++;
        if (C[A[i]] == 1) cnt++;
    } if (C[c] == 0) {
        C[c]++;
        if (C[c] == 1) cnt++;
    } ans = cnt;

    for (int i=1; i<=N-1; i++) {
        if (C[A[i-1]] > 0) { /* 이전 구간 첫 초밥 제거 */
            C[A[i-1]]--;
            if (C[A[i-1]] == 0) { /* 제거된 초밥이 그 종류에서 하나남은 초밥이면 */
                cnt--;
            }
        }

        C[A[(i+k-1)%N]]++;  /* 현재 구간 마지막 초밥 추가 */
        if (C[A[(i+k-1)%N]] == 1) { /* 추가된 초밥이 새로운 초밥의 종류이면 */
            cnt++;
        }

        if (C[c] == 0) { /* 쿠폰 초밥 */
            C[c]++;
            cnt++;
        }

        ans = max(ans, cnt);
    }

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

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

0개의 댓글