차량 기지에서 차량을 한 줄로 이어 기차를 만든다. 처음에는 차량이 하나도 없다.
명령 n개를 차례로 처리하라. 줄의 앞과 뒤 양쪽에서 붙이고 떼야 하므로, 표준 라이브러리의 양쪽 끝 큐(덱) 컨테이너를 쓴다.
- addf x: 번호 x인 차량을 맨 앞에 붙인다.
- addb x: 번호 x인 차량을 맨 뒤에 붙인다.
- cutf k: 맨 앞 차량을 떼는 일을 k번 한다. 남은 차량이 k량보다 적으면 있는 차량을 모두 떼고 멈춘다. 뗀 차량 번호를 뗀 차례대로(맨 앞 차량부터) 한 줄에 빈칸 하나로 띄워 출력한다. 뗀 차량이 없으면 -를 출력한다.
- cutb k: 맨 뒤 차량을 떼는 일을 k번 한다. 나머지 규칙은 cutf와 같고, 뗀 차례대로이므로 맨 뒤 차량부터 출력한다.
- rot k: 맨 앞 차량을 떼어 맨 뒤에 붙이는 일을 k번 한다. 아무것도 출력하지 않는다. 차량이 없으면 아무것도 하지 않는다.
모든 명령이 끝나면 남은 차량 수를 출력하고, 다음 줄에 남은 차량 번호를 앞에서부터 빈칸 하나로 띄워 출력한다. 남은 차량이 없으면 둘째 줄에 -를 출력한다.
입력
첫 줄에 n(1 ≤ n ≤ 5000). 다음 n줄에 명령 하나씩. addf·addb의 1 ≤ x ≤ 10^9, cutf·cutb의 1 ≤ k ≤ 10^9, rot의 0 ≤ k ≤ 10^9. 차량 번호는 서로 같을 수도 있다.
출력
cutf·cutb마다 한 줄(뗀 차량 번호, 없으면 -), 그다음 남은 차량 수, 그다음 남은 차량 번호(없으면 -)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 4개 언어 풀이
이 문제는 Python·Java·C#·C++만 받아요. 앞뒤 양쪽에서 O(1)로 넣고 빼는 컨테이너가 표준 라이브러리에 있는 언어들이에요. JavaScript·TypeScript 배열의 unshift·shift는 앞쪽을 빼고 넣을 때 칸을 모두 옮길 수 있고, C에는 컨테이너가 없으며, 크레이콘 목록의 끼우기(0, x)·자리빼기(0)도 뒤의 것을 한 칸씩 밀어요. 이름이 언어마다 달라요. Python collections.deque의 appendleft·append·popleft·pop·rotate, Java ArrayDeque의 addFirst·addLast·pollFirst·pollLast, C++ std::deque의 push_front·push_back·front+pop_front(pop_front()는 값을 돌려주지 않아요)·std::rotate예요. C#에는 Deque가 없어서 LinkedList<T>의 AddFirst·AddLast·RemoveFirst·RemoveLast를 써요. 떼는 횟수는 min(k, 남은 수)로 먼저 줄이고, 돌리기는 k를 차량 수로 나눈 나머지만큼만 하면 돼요(한 바퀴 돌면 제자리). Python rotate는 알아서 줄여 줘요. 함정 다섯: ① Python rotate(k)는 오른쪽으로 돌아서 뒤의 것이 앞으로 와요. 앞의 것을 뒤로 보내려면 rotate(-k)예요. C++ std::rotate(begin, begin + r, end)도 가운데 값이 '맨 앞이 될 칸'이라, end - r을 주면 반대로 돌아요. ② Python deque.pop()은 뒤에서 빼요. 앞에서 빼는 것은 popleft()예요. ③ Java ArrayDeque.push는 스택처럼 앞(addFirst)에 넣어요. 뒤에 붙이는 것은 addLast(add·offer)예요. ④ 줄이지 않고 k번 빼면 빈 컨테이너에서 빼게 돼요. C# train.First가 null이라 NullReferenceException으로 멈추고, Java pop·removeFirst는 NoSuchElementException을 던지며, pollFirst는 null을 줘서 int에 넣는 순간 NullPointerException이 나요. Python popleft는 IndexError를 내고, C++ front()는 정의되지 않은 동작이에요. ⑤ cutb는 맨 뒤 차량부터 떼니, 뗀 차례대로 적으면 기차에 붙어 있던 차례와 거꾸로예요.
Pythonmain.py · 27 줄
import sysfrom collections import dequelines = sys.stdin.read().split("\n")n = int(lines[0])train = deque() # 앞뒤 어느 쪽에서도 넣고 빼는 데 O(1)out = []for cmd in lines[1:n + 1]: op, arg = cmd.split() k = int(arg) if op == "addf": train.appendleft(k) elif op == "addb": train.append(k) elif op in ("cutf", "cutb"): # 남은 차량보다 많이 떼라고 하면 있는 만큼만 뗀다(빈 deque에서 빼면 IndexError) take = min(k, len(train)) if op == "cutf": cut = [train.popleft() for _ in range(take)] else: cut = [train.pop() for _ in range(take)] # 뗀 차례: 맨 뒤 차량부터 out.append(" ".join(map(str, cut)) if cut else "-") elif op == "rot": train.rotate(-k) # 음수는 왼쪽으로: 앞의 것이 뒤로 간다(빈 deque는 그대로)out.append(str(len(train)))out.append(" ".join(map(str, train)) if train else "-")print("\n".join(out))
JavaMain.java · 44 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayDeque;import java.util.StringJoiner;public class Main { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(in.readLine().trim()); ArrayDeque<Integer> train = new ArrayDeque<>(); // 앞뒤 어느 쪽에서도 넣고 빼는 데 O(1) StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) { String[] p = in.readLine().trim().split(" "); long k = Long.parseLong(p[1]); switch (p[0]) { case "addf" -> train.addFirst((int) k); case "addb" -> train.addLast((int) k); case "cutf", "cutb" -> { // 있는 만큼만 뗀다(빈 ArrayDeque에서 removeFirst·pop은 예외를 던진다) long take = Math.min(k, train.size()); StringJoiner cut = new StringJoiner(" "); for (long r = 0; r < take; r++) { int car = p[0].equals("cutf") ? train.pollFirst() : train.pollLast(); // 뒤는 맨 뒤 차량부터 cut.add(String.valueOf(car)); } out.append(take == 0 ? "-" : cut.toString()).append('\n'); } case "rot" -> { if (!train.isEmpty()) { long r = k % train.size(); // 한 바퀴 돌면 제자리다 for (long s = 0; s < r; s++) train.addLast(train.pollFirst()); } } default -> throw new IllegalArgumentException(p[0]); } } out.append(train.size()).append('\n'); StringJoiner items = new StringJoiner(" "); for (int x : train) items.add(String.valueOf(x)); // 앞에서 뒤로 돈다 out.append(train.isEmpty() ? "-" : items.toString()).append('\n'); System.out.print(out); }}
C#Main.cs · 51 줄
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { int n = int.Parse(Console.ReadLine()!.Trim()); // .NET에는 Deque가 없다. LinkedList<T>는 앞뒤에 넣고 빼는 데 O(1)이다 var train = new LinkedList<int>(); var output = new StringBuilder(); for (int i = 0; i < n; i++) { string[] p = Console.ReadLine()!.Trim().Split(' '); long k = long.Parse(p[1]); switch (p[0]) { case "addf": train.AddFirst((int)k); break; case "addb": train.AddLast((int)k); break; case "cutf": case "cutb": // 있는 만큼만 뗀다(비었는데 First를 읽으면 null이다) long take = Math.Min(k, train.Count); var cut = new List<int>(); for (long r = 0; r < take; r++) { if (p[0] == "cutf") { cut.Add(train.First!.Value); train.RemoveFirst(); } else { cut.Add(train.Last!.Value); train.RemoveLast(); } // 맨 뒤 차량부터 } output.Append(cut.Count == 0 ? "-" : string.Join(" ", cut)).Append('\n'); break; case "rot": if (train.Count > 0) { long r = k % train.Count; // 한 바퀴 돌면 제자리다 for (long s = 0; s < r; s++) { var node = train.First!; train.RemoveFirst(); train.AddLast(node); // 마디를 그대로 옮긴다 } } break; } } output.Append(train.Count).Append('\n'); output.Append(train.Count == 0 ? "-" : string.Join(" ", train)).Append('\n'); Console.Write(output); }}
C++main.cpp · 45 줄
#include <algorithm>#include <deque>#include <iostream>#include <string>int main() { std::ios::sync_with_stdio(false); int n; std::cin >> n; std::deque<int> train; // 앞뒤 어느 쪽에서도 넣고 빼는 데 O(1) for (int i = 0; i < n; i++) { std::string op; long long k; std::cin >> op >> k; if (op == "addf") { train.push_front((int)k); } else if (op == "addb") { train.push_back((int)k); } else if (op == "cutf" || op == "cutb") { // 빈 deque에서 front()·pop_front()는 정의되지 않은 동작이라, 있는 만큼만 뗀다 long long take = std::min(k, (long long)train.size()); if (take == 0) std::cout << '-'; for (long long r = 0; r < take; r++) { if (r > 0) std::cout << ' '; if (op == "cutf") { std::cout << train.front(); // pop_front()는 값을 돌려주지 않는다 train.pop_front(); } else { std::cout << train.back(); // 뗀 차례: 맨 뒤 차량부터 train.pop_back(); } } std::cout << '\n'; } else if (op == "rot") { if (!train.empty()) { long long r = k % (long long)train.size(); // 한 바퀴 돌면 제자리다 // [begin, begin + r)이 끝으로 간다: 앞의 r개가 뒤로 std::rotate(train.begin(), train.begin() + r, train.end()); } } } std::cout << train.size() << '\n'; if (train.empty()) std::cout << "-\n"; for (std::size_t i = 0; i < train.size(); i++) std::cout << train[i] << (i + 1 < train.size() ? ' ' : '\n');}