과학 축제의 체험 부스는 같은 부스를 고른 학생이 k명 모일 때마다 그 k명을 한 조로 묶어 들여보낸다.
학생 n명이 온 차례대로 이름과 고른 부스 번호 b가 주어진다.
학생이 오면 그 부스의 대기 줄 맨 뒤에 선다.
어떤 부스의 대기 줄이 k명이 되면 그 순간 한 줄에 부스 번호, 쌍점(:), 그리고 그 k명의 이름을 줄 선 차례대로 출력하고 그 부스의 대기 줄을 비운다.
쌍점 뒤와 이름 사이는 빈칸 하나로 띄운다(예: 30: mina seo).
학생이 모두 온 뒤에는 한 줄에 left와 아직 기다리는 학생의 수를 빈칸 하나로 띄워 출력한다.
그 뒤에 기다리는 학생이 있는 부스마다 한 줄씩, 위와 같은 꼴로 부스 번호와 기다리는 이름들을 줄 선 차례대로 출력한다.
이때 부스의 차례는 그 부스 번호가 입력에 처음 나온 차례이다.
그 부스에서 조가 이미 들어간 적이 있어도 처음 나온 차례는 바뀌지 않는다.
기다리는 학생이 없는 부스는 출력하지 않는다.
입력
첫 줄에 n과 k(1 ≤ n ≤ 1,000, 1 ≤ k ≤ 10), 다음 n줄에 이름과 부스 번호 b(1 ≤ b ≤ 1,000,000,000)가 빈칸 하나로 띄워 주어진다. 수는 모두 정수이고 쉼표와 앞의 0 없이 숫자만 주어진다. 이름은 영어 소문자 1~8글자이고, 같은 이름의 학생이 여럿 있을 수 있다
출력
조가 들어갈 때마다 한 줄, 그다음 left 줄, 그다음 기다리는 학생이 있는 부스마다 한 줄(부스 번호는 쉼표 없이 숫자만)
예시 1 · stdin
7 2
mina 30
jun 7
seo 30
dan 7
eli 7
ari 12
bo 30
stdout
30: mina seo
7: jun dan
left 3
30: bo
7: eli
12: ari
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
부스 번호를 열쇠로, 기다리는 이름들의 목록을 값으로 두면 같은 부스끼리 모을 수 있어요. 마지막에 '처음 나온 차례'로 돌아야 해서, 사전이 열쇠를 어떤 차례로 내주는지가 이 문제의 갈림길이에요. Python의 dict, JS·TS의 Map, Java의 LinkedHashMap, 크레이콘의 사전()(열쇠목록)은 열쇠를 처음 넣은 차례대로 돌아요. C#의 Dictionary는 도는 차례를 문서에서 약속하지 않고 C++의 unordered_map도 마찬가지라서, 처음 나온 부스 번호를 목록에 따로 적어 두고 그 목록을 돌아요. C에는 사전이 없으니 부스 번호 배열을 앞에서부터 찾고, 없으면 끝에 더해요. 그러면 배열의 차례가 곧 처음 나온 차례예요. 함정 하나: JS의 보통 객체 {}는 30, 7, 12처럼 정수 꼴인 열쇠를 넣은 차례가 아니라 작은 것부터 돌아요. 예시의 마지막 세 줄이 7: eli, 12: ari, 30: bo 차례가 돼요. 함정 둘: Java의 HashMap은 넣은 차례를 기억하지 않아요. 예시에서 역시 7, 12, 30 차례로 나와요. 함정 셋: C++의 std::map은 언제나 열쇠가 작은 것부터 돌아서 같은 틀린 답이 나와요. 함정 넷: 조가 들어갈 때 열쇠를 아예 지우면(Python del waiting[b]) 그 부스가 다시 나왔을 때 맨 뒤에 새로 들어가요. 예시의 30번 부스는 맨 처음 나왔는데도 30: bo가 마지막 줄로 밀려요. 열쇠는 그대로 두고 값만 빈 목록으로 바꿔요(Python waiting[b] = [], JS names.length = 0, Java names.clear(), C# names.Clear(), C++ names.clear(), 크레이콘 waiting[b] = []).
Pythonmain.py · 15 줄
n, k = map(int, input().split())waiting = {} # 부스 번호 → 기다리는 이름들. dict는 열쇠를 처음 넣은 차례를 기억한다for _ in range(n): name, b = input().split() b = int(b) if b not in waiting: waiting[b] = [] waiting[b].append(name) if len(waiting[b]) == k: print(f"{b}: {' '.join(waiting[b])}") waiting[b] = [] # 열쇠는 지우지 않고 값만 비운다: 처음 나온 차례가 남는다print("left", sum(len(names) for names in waiting.values()))for b, names in waiting.items(): if names: print(f"{b}: {' '.join(names)}")
JavaScriptmain.js · 23 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, k] = lines[0].split(" ").map(Number);// Map은 열쇠를 처음 넣은 차례대로 돈다(보통 객체 {}는 정수 열쇠를 작은 것부터 돈다)const waiting = new Map();const out = [];for (let i = 1; i <= n; i++) { const [name, t] = lines[i].split(" "); const b = Number(t); if (!waiting.has(b)) waiting.set(b, []); const names = waiting.get(b); names.push(name); if (names.length === k) { out.push(`${b}: ${names.join(" ")}`); names.length = 0; // 열쇠는 지우지 않고 값만 비운다 }}let left = 0;for (const names of waiting.values()) left += names.length;out.push(`left ${left}`);for (const [b, names] of waiting) { if (names.length > 0) out.push(`${b}: ${names.join(" ")}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 28 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, k] = lines[0].split(" ").map(Number);// Map은 열쇠를 처음 넣은 차례대로 돈다(보통 객체 {}는 정수 열쇠를 작은 것부터 돈다)const waiting = new Map<number, string[]>();const out: string[] = [];for (let i = 1; i <= n; i++) { const [name, t] = lines[i].split(" "); const b: number = Number(t); let names: string[] | undefined = waiting.get(b); if (names === undefined) { names = []; waiting.set(b, names); } names.push(name); if (names.length === k) { out.push(`${b}: ${names.join(" ")}`); names.length = 0; // 열쇠는 지우지 않고 값만 비운다 }}let left = 0;for (const names of waiting.values()) left += names.length;out.push(`left ${left}`);for (const [b, names] of waiting) { if (names.length > 0) out.push(`${b}: ${names.join(" ")}`);}console.log(out.join("\n"));
JavaMain.java · 37 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] first = br.readLine().split(" "); int n = Integer.parseInt(first[0]), k = Integer.parseInt(first[1]); // LinkedHashMap은 열쇠를 처음 넣은 차례대로 돈다(HashMap은 차례를 지키지 않는다) Map<Integer, List<String>> waiting = new LinkedHashMap<>(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) { String[] parts = br.readLine().split(" "); int b = Integer.parseInt(parts[1]); List<String> names = waiting.computeIfAbsent(b, key -> new ArrayList<>()); names.add(parts[0]); if (names.size() == k) { sb.append(b).append(": ").append(String.join(" ", names)).append('\n'); names.clear(); // 열쇠는 지우지 않고 값만 비운다 } } int left = 0; for (List<String> names : waiting.values()) left += names.size(); sb.append("left ").append(left).append('\n'); for (Map.Entry<Integer, List<String>> e : waiting.entrySet()) { if (!e.getValue().isEmpty()) { sb.append(e.getKey()).append(": ").append(String.join(" ", e.getValue())).append('\n'); } } System.out.print(sb); }}
C#Main.cs · 43 줄
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { string[] first = Console.ReadLine()!.Split(' '); int n = int.Parse(first[0]), k = int.Parse(first[1]); var waiting = new Dictionary<int, List<string>>(); var order = new List<int>(); // Dictionary는 도는 차례를 약속하지 않으므로 처음 나온 차례를 따로 적는다 var sb = new StringBuilder(); for (int i = 0; i < n; i++) { string[] parts = Console.ReadLine()!.Split(' '); int b = int.Parse(parts[1]); if (!waiting.TryGetValue(b, out List<string>? names)) { names = new List<string>(); waiting[b] = names; order.Add(b); } names.Add(parts[0]); if (names.Count == k) { sb.Append(b).Append(": ").Append(string.Join(" ", names)).Append('\n'); names.Clear(); // 열쇠는 지우지 않고 값만 비운다 } } int left = 0; foreach (int b in order) left += waiting[b].Count; sb.Append("left ").Append(left).Append('\n'); foreach (int b in order) { if (waiting[b].Count > 0) { sb.Append(b).Append(": ").Append(string.Join(" ", waiting[b])).Append('\n'); } } Console.Write(sb); }}
C++main.cpp · 39 줄
#include <iostream>#include <string>#include <unordered_map>#include <vector>using namespace std;static void printGroup(int b, const vector<string>& names) { cout << b << ':'; for (const string& s : names) cout << ' ' << s; cout << '\n';}int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, k; cin >> n >> k; unordered_map<int, vector<string>> waiting; vector<int> order; // map은 열쇠 크기순, unordered_map은 제멋대로 돌므로 처음 나온 차례를 따로 적는다 for (int i = 0; i < n; i++) { string name; int b; cin >> name >> b; if (waiting.find(b) == waiting.end()) order.push_back(b); vector<string>& names = waiting[b]; names.push_back(name); if ((int)names.size() == k) { printGroup(b, names); names.clear(); // 열쇠는 지우지 않고 값만 비운다 } } size_t left = 0; for (int b : order) left += waiting[b].size(); cout << "left " << left << '\n'; for (int b : order) { if (!waiting[b].empty()) printGroup(b, waiting[b]); } return 0;}
Cmain.c · 43 줄
#include <stdio.h>#include <string.h>/* C에는 사전이 없다: 부스 번호를 처음 나온 차례대로 배열에 적고 앞에서부터 찾는다 */int booth[1000]; /* booth[g]: g번째로 처음 나온 부스 번호 */int count[1000]; /* 그 부스에서 기다리는 사람 수 */char names[1000][10][9]; /* 그 부스에서 기다리는 이름들(k ≤ 10, 이름 ≤ 8글자) */static void print_group(int g) { printf("%d:", booth[g]); for (int j = 0; j < count[g]; j++) printf(" %s", names[g][j]); printf("\n");}int main(void) { int n, k, groups = 0; if (scanf("%d %d", &n, &k) != 2) return 0; for (int i = 0; i < n; i++) { char name[9]; int b; if (scanf("%8s %d", name, &b) != 2) return 0; int g = 0; while (g < groups && booth[g] != b) g++; if (g == groups) { booth[groups] = b; count[groups] = 0; groups++; } strcpy(names[g][count[g]], name); count[g]++; if (count[g] == k) { print_group(g); count[g] = 0; /* 자리는 그대로 두고 수만 0으로 */ } } int left = 0; for (int g = 0; g < groups; g++) left += count[g]; printf("left %d\n", left); for (int g = 0; g < groups; g++) { if (count[g] > 0) print_group(g); } return 0;}
Craykonmain.cray · 32 줄
첫줄 = 콘솔.수들읽기();n = 첫줄[0];k = 첫줄[1];waiting = 사전(); // 부스 번호 → 기다리는 이름들. 사전은 열쇠를 처음 넣은 차례를 기억한다반복 (i = 0; i < n; i++){ parts = 콘솔.줄읽기().나누기(); b = parts[1].수로변환(); 만약 (!waiting.있나(b)) { waiting[b] = []; } waiting[b].넣기(parts[0]); 만약 (waiting[b].개수 == k) { 콘솔.쓰기(b + ": " + waiting[b].잇기(" ")); waiting[b] = []; // 열쇠는 빼지 않고 값만 비운다 }}left = 0;각각 (b 에서 waiting.열쇠목록){ left += waiting[b].개수;}콘솔.쓰기("left " + left);각각 (b 에서 waiting.열쇠목록){ 만약 (waiting[b].개수 > 0) { 콘솔.쓰기(b + ": " + waiting[b].잇기(" ")); }}