There is one list that holds words in order, and it starts empty. Like save slots in a game, you can save the current list into a named slot and load it later. The first line gives the number of commands q, and each of the next q lines gives one command. add w puts the word w at the end of the list. remove w removes the first w in the list. If the list has no w, it does nothing. save s saves the current state of the list into the slot named s. If the slot already holds something, it is replaced. load s returns the list to the state saved in slot s. If nothing was ever saved in slot s, it does nothing. A slot's contents change only when that slot is saved again. Editing the list after a load leaves the slot as it was. Each time print appears, print the list's words on one line separated by single spaces. If the list is empty, print -.
Input
1 ≤ q ≤ 2000. Words and slot names are 1 to 10 lowercase English letters or digits. The whole output is at most 100,000 characters
Output
One line for each print
Example 1 · stdin
10
add red
add blue
save s1
remove red
add green
print
load s1
add pink
load s1
print
stdout
blue green
red blue
Example 2 · stdin
7
remove x
print
load nothing
add x
add x
remove x
print
stdout
-
x
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
The key is to copy both when saving and when loading. Lists in Python, JS, TS, Java, C# and Craykon are references, so slots[s] = doc only adds another pointer to the same list, and editing doc afterwards changes the slot too. Loading with doc = slots[s] is the same: an add after the load spoils the slot, which shows up on the second load. Copies are Python doc.copy() (or doc[:], list(doc)), JS/TS [...doc] (or doc.slice()), Java new ArrayList<>(doc), C# new List<string>(doc) and Craykon doc.GetRange(0, doc.Count) (doc.부분목록(0, doc.개수)). A C++ vector is a value, so slots[s] = doc copies by itself, and in C, putting the array inside a struct lets struct assignment copy the whole thing (a bare array cannot be assigned). The second trap is removing by value. Python remove raises ValueError when the item is missing, so ask with in first; Java remove(Object), C# Remove and Craykon Remove (빼기) just return false. JS has no remove-by-value method, so you write splice(indexOf(w), 1); when w is missing indexOf is -1 and splice(-1, 1) removes the last word. Every one of them removes only the first match.
Pythonmain.py · 24 lines
import syslines = sys.stdin.read().split("\n")q = int(lines[0])doc = []slots = {} # 이름 → 저장해 둔 목록out = []for line in lines[1:q + 1]: cmd, *arg = line.split() if cmd == "add": doc.append(arg[0]) elif cmd == "remove": if arg[0] in doc: # 없으면 remove가 ValueError를 낸다 doc.remove(arg[0]) # 맨 앞의 것 하나만 뺀다 elif cmd == "save": slots[arg[0]] = doc.copy() # 복사해 둬야 나중에 doc을 고쳐도 그대로다 elif cmd == "load": if arg[0] in slots: doc = slots[arg[0]].copy() # 불러올 때도 복사 — 아니면 고칠 때 저장한 것도 바뀐다 else: out.append(" ".join(doc) if doc else "-")print("\n".join(out))
JavaScriptmain.js · 22 lines
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);let doc = [];const slots = new Map(); // 이름 → 저장해 둔 배열const out = [];for (const line of lines.slice(1, q + 1)) { const [cmd, w] = line.trim().split(" "); if (cmd === "add") { doc.push(w); } else if (cmd === "remove") { const at = doc.indexOf(w); if (at !== -1) doc.splice(at, 1); // -1을 splice에 넣으면 마지막 것이 빠진다 } else if (cmd === "save") { slots.set(w, [...doc]); // 복사해 둔다 } else if (cmd === "load") { if (slots.has(w)) doc = [...slots.get(w)]; // 불러올 때도 복사 } else { out.push(doc.length > 0 ? doc.join(" ") : "-"); }}console.log(out.join("\n"));
TypeScriptmain.ts · 24 lines
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);let doc: string[] = [];const slots = new Map<string, string[]>(); // 이름 → 저장해 둔 배열const out: string[] = [];for (const line of lines.slice(1, q + 1)) { const [cmd, w] = line.trim().split(" "); if (cmd === "add") { doc.push(w); } else if (cmd === "remove") { const at = doc.indexOf(w); if (at !== -1) doc.splice(at, 1); // -1을 splice에 넣으면 마지막 것이 빠진다 } else if (cmd === "save") { slots.set(w, [...doc]); // 복사해 둔다 } else if (cmd === "load") { const saved = slots.get(w); if (saved !== undefined) doc = [...saved]; // 불러올 때도 복사 } else { out.push(doc.length > 0 ? doc.join(" ") : "-"); }}console.log(out.join("\n"));
JavaMain.java · 26 lines
import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int q = Integer.parseInt(br.readLine().trim()); List<String> doc = new ArrayList<>(); Map<String, List<String>> slots = new HashMap<>(); // 이름 → 저장해 둔 목록 StringBuilder out = new StringBuilder(); for (int i = 0; i < q; i++) { String[] p = br.readLine().trim().split(" "); switch (p[0]) { case "add" -> doc.add(p[1]); case "remove" -> doc.remove(p[1]); // remove(Object): 맨 앞의 것 하나, 없으면 false case "save" -> slots.put(p[1], new ArrayList<>(doc)); // 복사해 둔다 case "load" -> { if (slots.containsKey(p[1])) doc = new ArrayList<>(slots.get(p[1])); // 불러올 때도 복사 } default -> out.append(doc.isEmpty() ? "-" : String.join(" ", doc)).append('\n'); } } System.out.print(out); }}
C#Main.cs · 38 lines
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { int q = int.Parse(Console.ReadLine().Trim()); var doc = new List<string>(); var slots = new Dictionary<string, List<string>>(); // 이름 → 저장해 둔 목록 var sb = new StringBuilder(); for (int i = 0; i < q; i++) { string[] p = Console.ReadLine().Trim().Split(' '); switch (p[0]) { case "add": doc.Add(p[1]); break; case "remove": doc.Remove(p[1]); // 맨 앞의 것 하나, 없으면 false break; case "save": slots[p[1]] = new List<string>(doc); // 복사해 둔다 break; case "load": if (slots.TryGetValue(p[1], out var saved)) doc = new List<string>(saved); // 불러올 때도 복사 break; default: sb.Append(doc.Count > 0 ? string.Join(" ", doc) : "-").Append('\n'); break; } } Console.Write(sb); }}
C++main.cpp · 35 lines
#include <algorithm>#include <iostream>#include <map>#include <string>#include <vector>int main() { int q; std::cin >> q; std::vector<std::string> doc; std::map<std::string, std::vector<std::string>> slots; // 이름 → 저장해 둔 목록 std::string out; for (int i = 0; i < q; i++) { std::string cmd, w; std::cin >> cmd; if (cmd != "print") std::cin >> w; if (cmd == "add") { doc.push_back(w); } else if (cmd == "remove") { auto it = std::find(doc.begin(), doc.end(), w); if (it != doc.end()) doc.erase(it); // end()를 지우면 정의되지 않은 동작 } else if (cmd == "save") { slots[w] = doc; // vector는 값이라 대입이 곧 복사 } else if (cmd == "load") { auto it = slots.find(w); if (it != slots.end()) doc = it->second; // 여기서도 복사 } else { if (doc.empty()) out += "-"; for (size_t j = 0; j < doc.size(); j++) out += (j ? " " : "") + doc[j]; out += "\n"; } } std::cout << out;}
Cmain.c · 66 lines
#include <stdio.h>#include <string.h>#define CAP 2000 /* 명령이 많아야 2000개라 목록도 이름도 2000개를 넘지 않는다 *//* 목록 = 낱말 번호 배열과 길이. 구조체 안의 배열은 대입하면 통째로 복사된다 */typedef struct { int len; int w[CAP];} Doc;static char words[CAP][11], slot_names[CAP][11];static int word_count = 0, slot_count = 0;static Doc doc, slots[CAP];static int word_id(const char *s) { for (int i = 0; i < word_count; i++) if (strcmp(words[i], s) == 0) return i; strcpy(words[word_count], s); return word_count++;}static int find_slot(const char *s) { for (int i = 0; i < slot_count; i++) if (strcmp(slot_names[i], s) == 0) return i; return -1;}int main(void) { int q; char cmd[8], w[11]; scanf("%d", &q); for (int i = 0; i < q; i++) { scanf("%7s", cmd); if (strcmp(cmd, "print") == 0) { if (doc.len == 0) printf("-"); for (int j = 0; j < doc.len; j++) printf(j ? " %s" : "%s", words[doc.w[j]]); printf("\n"); continue; } scanf("%10s", w); if (strcmp(cmd, "add") == 0) { doc.w[doc.len++] = word_id(w); } else if (strcmp(cmd, "remove") == 0) { int id = word_id(w); for (int j = 0; j < doc.len; j++) { if (doc.w[j] == id) { /* 맨 앞의 것을 빼고 뒤를 한 칸씩 당긴다 */ memmove(doc.w + j, doc.w + j + 1, sizeof(int) * (doc.len - j - 1)); doc.len--; break; } } } else if (strcmp(cmd, "save") == 0) { int s = find_slot(w); if (s < 0) { s = slot_count++; strcpy(slot_names[s], w); } slots[s] = doc; /* 구조체 대입 = 복사 */ } else { int s = find_slot(w); if (s >= 0) doc = slots[s]; } } return 0;}
Craykonmain.cray · 36 lines
q = Console.ReadLine().ToNumber();doc = [];slots = Dict(); // 이름 → 저장해 둔 목록for (i = 0; i < q; i++){ p = Console.ReadLine().Trim().Split(); switch (p[0]) { case "add": doc.Add(p[1]); break; case "remove": doc.Remove(p[1]); // 맨 앞의 것 하나, 없으면 거짓 break; case "save": slots[p[1]] = doc.GetRange(0, doc.Count); // 복사해 둔다 break; case "load": if (slots.Contains(p[1])) { doc = slots[p[1]].GetRange(0, slots[p[1]].Count); // 불러올 때도 복사 } break; default: if (doc.Count > 0) { Console.WriteLine(doc.Join(" ")); } else { Console.WriteLine("-"); } break; }}