Post

[BOJ] 회전 초밥 - 2531 (S1)

[BOJ] 회전 초밥 - 2531 (S1)
시간 제한메모리 제한
1 초256 MB

문제

회전 초밥 음식점에는 벨트 위에 같은 종류의 초밥이 둘 이상 있을 수 있다.

새로 문을 연 회전 초밥 가게가 손님을 끌기 위해 다음과 같은 이벤트를 한다.

  1. 벨트의 임의의 한 위치부터 k개의 접시를 연속해서 먹을 경우 할인된 정액 가격으로 제공한다.
  2. 각 고객에게 초밥의 종류 하나가 쓰인 쿠폰을 발행하고, 1번 행사에 참가할 경우 이 쿠폰에 적혀진 종류의 초밥 하나를 추가로 무료로 제공한다. 만약 이 번호에 적혀진 초밥이 회전 초밥 벨트 위에 없을 경우, 요리사가 새로 만들어 손님에게 제공한다.

위 할인 행사에 참여하여 가능한 한 다양한 종류의 초밥을 먹으려고 한다. 먹을 수 있는 초밥 가짓수의 최댓값을 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에는 회전 초밥 벨트에 놓인 접시의 수 N, 초밥의 가짓수 d, 연속해서 먹는 접시의 수 k, 쿠폰 번호 c가 주어진다. 단, 2 ≤ N ≤ 30,000, 2 ≤ d ≤ 3,000, 2 ≤ k ≤ 3,000 (k ≤ N), 1 ≤ c ≤ d이다.

출력

주어진 회전 초밥 벨트에서 먹을 수 있는 초밥의 최대 가짓수를 출력하시오.

풀이

슬라이딩 윈도우 기법을 사용하는 문제이다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from collections import defaultdict

N, d, k, c = map(int, input().split())
sushi_list = [int(input()) for _ in range(N)]

counter = defaultdict(int)
kind = 0

for i in range(k):
    if counter[sushi_list[i]] == 0:
        kind += 1
    counter[sushi_list[i]] += 1

# 쿠폰
max_kind = kind + (1 if counter[c] == 0 else 0)

for i in range(1, N):
    remove = sushi_list[i - 1]
    counter[remove] -= 1
    if counter[remove] == 0:  # 더 이상 없으면 종류 수 감소
        kind -= 1

    cur = sushi_list[(i + k - 1) % N]
    if counter[cur] == 0:
        kind += 1
    counter[cur] += 1

    # 쿠폰
    total = kind + (1 if counter[c] == 0 else 0)
    max_kind = max(max_kind, total)  # 최대 종류 수 갱신

print(max_kind)

시간 복잡도

O(N)

This post is licensed under CC BY 4.0 by the author.