본문 바로가기
Coding Test/Problems

[BOJ | Python] 28107번: 회전초밥

by haerr 2025. 9. 28.

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

 

문제

회전 초밥 가게에 명의 손님이 있고, 요리사는 개의 초밥을 순서대로 만든다. 요리사가 초밥을 만들 경우, 번 손님부터 번 손님의 순서대로 그 초밥을 받게 된다. 만약 먼저 초밥을 받는 손님이 초밥을 먹을 경우, 뒤의 손님들은 해당 초밥을 먹을 수 없다. 만약 아무도 해당 초밥을 먹지 않는다면, 초밥은 버려진다.

명의 손님은 각자 먹고 싶은 초밥이 적힌 주문 목록을 가지고 있다. 목록에 적힌 초밥의 순서에 상관 없이 만약 목록에 적혀있는 초밥이 앞에 오면 반드시 먹는다. 만약, 목록에 적히지 않은 초밥을 받는다면 그 초밥은 반드시 먹지 않는다. 단, 손님들은 다양한 초밥을 먹고 싶어하기 때문에 각 종류의 초밥은 최대 한 번만 먹는다.

각 손님의 주문 목록과 순서대로 만들어지는 개의 초밥이 주어질 때, 각 손님이 먹게 되는 초밥의 개수를 구해 보자.

 

입력

첫 번째 줄에 손님의 수 N과 초밥의 수 M이 공백으로 구분되어 주어진다. (1≤ N S 100 000;1≤ M S 200 000)

두 번째 줄부터 N개의 줄에 걸쳐 각 손님에 대한 주문 목록을 나타내는 정수 K와 A1, A2, , Ax가 공백으로 구분되어 순서대로 주어진다. K는 주문 목록에 적힌 초밥 종류의 개수이며, A,는 주문 목록에 적힌 초밥 종류이다. (1≤ Ai ≤ 200 000)

각 손님의 주문 목록에 적힌 초밥 종류는 모두 다르며, 모든 손님에 대해 k의 합이 200 000 이하임이 보장된다.

N + 2번째 줄에 요리되는 초밥의 종류를 나타내는 N개의 정수 B1, B2,..., Bw이 공백으로 구분되어 순서대로 주어진다. (1≤ B, ≤ 200000)

 

출력

한 줄에 개의 정수 을 공백으로 구분하여 출력한다. 번 손님이 먹은 초밥의 개수를 의미한다.

 

풀이

import sys
input = sys.stdin.readline

N, M = map(int, input().split())

# 손님별 먹은 개수
ans = [0] * N

# 초밥별 → 손님 리스트
from collections import defaultdict
pref = defaultdict(list)

for i in range(N):
    data = list(map(int, input().split()))
    k, likes = data[0], data[1:]
    for sushi in likes:
        pref[sushi].append(i)

# 각 초밥별 포인터
cur = {sushi: 0 for sushi in pref}

# 손님이 초밥 먹었는지 여부
eaten = [set() for _ in range(N)]

sushis = list(map(int, input().split()))

for s in sushis:
    if s not in pref:  # 선호자 없음
        continue
    lst = pref[s]
    p = cur[s]
    # 아직 먹을 수 있는 손님 찾기
    while p < len(lst) and s in eaten[lst[p]]:
        p += 1
    if p < len(lst):
        customer = lst[p]
        ans[customer] += 1
        eaten[customer].add(s)
        cur[s] = p + 1
    else:
        cur[s] = p  # 끝까지 간 경우 유지

print(" ".join(map(str, ans)))