3 13
num add 5
word add kiwi
num add 0012
num add 300
num add 5
num add 7
word add fig
word add kiwi
num del 300
num show
word show
word del plum
word show
stdout
7 5
kiwi fig
kiwi fig
main.py
エラー一覧00F8 ↓ · ⇧F8 ↑
入力(stdin)
実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。
$ 準備完了
コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。
ほかの言語では?言語別の解答を見る · 4 言語の解答
この問題はジェネリクスのある TypeScript・Java・C#・C++ だけを受け付けます(C++ はクラステンプレート)。 Python・JavaScript は型を書かないのでクラス一つが最初から何でも入れられ(Python の TypeVar は書いておくだけで実行時には検査しません)、C と Craykon には型引数がありません。 四つの言語は「同じものを探す」やり方が違います。 TS の indexOf は === で探すので、数と文字列は値で比べられます。 Java は Recent<int> と書けないので Recent<Integer> に入れ、T どうしは equals で比べます。 C# は制約のない T に == を使うとコンパイルエラーなので EqualityComparer<T>.Default.Equals を使い、Recent<int> はボックス化せずに入れます。 C++ のテンプレートは T ごとに別のコードが作られ、std::find がその T の == を呼びます。 落とし穴は三つ:① Java のジェネリックなコードで items.get(i) == x は同じオブジェクトかどうかを聞きます。 Integer は -128〜127 だけあらかじめ作ったオブジェクトを共有するので小さい数では正しく見えますが、1000 や読み込んだ単語は値が同じでも別のオブジェクトなので、取り除かれずに二回入ります。 ② TS・C++ で整数を読んだ文字列のまま Recent<string> に入れると、007 と 7 が別の項目になり、出力も 007 になります。 Number(x)・std::stoll で変換して Recent<number>・Recent<long long> に入れます。 ③ C# で == を使うために where T : class 制約をつけるとコンパイルは通りますが、ジェネリックの中の == は string の値の比較ではなく参照の比較なので、読み込んだ同じ単語を違うものとみなします(しかも int は入れられません)。
TypeScriptmain.ts · 39 行
import { readFileSync } from "node:fs";// 가장 최근 것부터 k개까지만 기억하는 목록. T가 무엇이든 같은 코드로 쓴다class Recent<T> { private items: T[] = []; constructor(private readonly capacity: number) {} add(x: T): void { this.remove(x); // 이미 있으면 빼고 this.items.unshift(x); // 맨 앞(가장 최근)에 넣고 if (this.items.length > this.capacity) this.items.pop(); // 넘치면 가장 오래된 것을 버린다 } remove(x: T): void { const i = this.items.indexOf(x); // indexOf는 ===로 찾는다: 수와 문자열은 값으로 같다 if (i >= 0) this.items.splice(i, 1); } show(): string { return this.items.length === 0 ? "-" : this.items.join(" "); }}const lines = readFileSync(0, "utf8").split("\n");const [k, q] = lines[0].split(" ").map(Number);const nums = new Recent<number>(k); // 수는 수로 바꿔 담아야 "007"과 "7"이 같아진다const words = new Recent<string>(k);const out: string[] = [];for (const line of lines.slice(1, 1 + q)) { const [kind, cmd, arg] = line.trim().split(" "); if (kind === "num") { if (cmd === "show") out.push(nums.show()); else if (cmd === "add") nums.add(Number(arg)); else nums.remove(Number(arg)); } else { if (cmd === "show") out.push(words.show()); else if (cmd === "add") words.add(arg); else words.remove(arg); }}console.log(out.join("\n"));
JavaMain.java · 63 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;// 가장 최근 것부터 capacity개까지만 기억하는 목록. T가 무엇이든 같은 코드로 쓴다class Recent<T> { private final List<T> items = new ArrayList<>(); private final int capacity; Recent(int capacity) { this.capacity = capacity; } void add(T x) { remove(x); items.add(0, x); if (items.size() > capacity) items.remove(items.size() - 1); } void remove(T x) { // T는 객체라서 ==는 같은 객체인지를 묻는다. 값이 같은지는 equals로 묻는다 for (int i = 0; i < items.size(); i++) { if (items.get(i).equals(x)) { items.remove(i); return; } } } String show() { if (items.isEmpty()) return "-"; StringBuilder sb = new StringBuilder(); for (T x : items) { if (sb.length() > 0) sb.append(' '); sb.append(x); } return sb.toString(); }}public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] first = br.readLine().trim().split(" "); int k = Integer.parseInt(first[0]), q = Integer.parseInt(first[1]); Recent<Integer> nums = new Recent<>(k); // Recent<int>는 안 된다: 제네릭에는 Integer로 담는다 Recent<String> words = new Recent<>(k); StringBuilder out = new StringBuilder(); for (int e = 0; e < q; e++) { String[] p = br.readLine().trim().split(" "); boolean isNum = p[0].equals("num"); if (p[1].equals("show")) { out.append(isNum ? nums.show() : words.show()).append('\n'); } else if (isNum) { int x = Integer.parseInt(p[2]); // "007"도 7로 읽힌다 if (p[1].equals("add")) nums.add(x); else nums.remove(x); } else { if (p[1].equals("add")) words.add(p[2]); else words.remove(p[2]); } } System.out.print(out); }}
C#Main.cs · 57 行
using System;using System.Collections.Generic;using System.IO;using System.Text;// 가장 최근 것부터 capacity개까지만 기억하는 목록. T가 무엇이든 같은 코드로 쓴다class Recent<T>{ private readonly List<T> items = new List<T>(); private readonly int capacity; // 제약 없는 T에는 ==를 쓸 수 없다(컴파일 오류). 그 T에 맞는 같음은 EqualityComparer가 안다 private static readonly EqualityComparer<T> Same = EqualityComparer<T>.Default; public Recent(int capacity) { this.capacity = capacity; } public void Add(T x) { Remove(x); items.Insert(0, x); if (items.Count > capacity) items.RemoveAt(items.Count - 1); } public void Remove(T x) { int i = items.FindIndex(y => Same.Equals(y, x)); if (i >= 0) items.RemoveAt(i); } public string Show() => items.Count == 0 ? "-" : string.Join(" ", items);}class Program{ static void Main() { var input = Console.In; string[] first = input.ReadLine()!.Trim().Split(' '); int k = int.Parse(first[0]), q = int.Parse(first[1]); var nums = new Recent<int>(k); // C# 제네릭은 int를 포장(boxing) 없이 담는다 var words = new Recent<string>(k); var sb = new StringBuilder(); for (int e = 0; e < q; e++) { string[] p = input.ReadLine()!.Trim().Split(' '); bool isNum = p[0] == "num"; if (p[1] == "show") sb.Append(isNum ? nums.Show() : words.Show()).Append('\n'); else if (isNum) { int x = int.Parse(p[2]); // "007"도 7로 읽힌다 if (p[1] == "add") nums.Add(x); else nums.Remove(x); } else if (p[1] == "add") words.Add(p[2]); else words.Remove(p[2]); } Console.Write(sb); }}
C++main.cpp · 59 行
#include <algorithm>#include <deque>#include <iostream>#include <sstream>#include <string>// 가장 최근 것부터 capacity개까지만 기억하는 목록. 템플릿이라 T마다 따로 만들어진다template <typename T>class Recent {public: explicit Recent(std::size_t capacity) : capacity_(capacity) {} void add(const T &x) { remove(x); items_.push_front(x); if (items_.size() > capacity_) items_.pop_back(); } void remove(const T &x) { auto it = std::find(items_.begin(), items_.end(), x); // T의 ==로 찾는다 if (it != items_.end()) items_.erase(it); } std::string show() const { if (items_.empty()) return "-"; std::ostringstream os; for (std::size_t i = 0; i < items_.size(); i++) os << (i ? " " : "") << items_[i]; return os.str(); }private: std::deque<T> items_; std::size_t capacity_;};int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::size_t k; int q; std::cin >> k >> q; Recent<long long> nums(k); // 수는 수로 읽어야 "007"과 "7"이 같아진다 Recent<std::string> words(k); std::string kind, cmd, arg; std::string out; for (int e = 0; e < q; e++) { std::cin >> kind >> cmd; if (cmd == "show") { out += (kind == "num" ? nums.show() : words.show()) + '\n'; continue; } std::cin >> arg; if (kind == "num") { long long x = std::stoll(arg); if (cmd == "add") nums.add(x); else nums.remove(x); } else { if (cmd == "add") words.add(arg); else words.remove(arg); } } std::cout << out;}