{ }codelper
类方法P0079

共用的号码牌

用窗口类来模拟一个有 m 个窗口的店。
号码牌的流水号是所有窗口共用的一个值,所以在类里只放一个(类变量、静态字段),而每个窗口领到的号码牌列表由各窗口对象分别持有。
窗口是编号 1 到 m 的 m 个不同对象。
第一行给出 m 和命令数 q,接下来 q 行每行一个命令。"take w":流水号加 1(第一张为 1),把这张号码牌放到窗口 w 列表的末尾,输出 "流水号 列表长度"(列表长度是放入后窗口 w 列表中的号码牌数)。"reset w":只清空窗口 w 的列表。
其他窗口和流水号保持不变。
没有输出。"show w":在一行中先输出窗口 w 列表中的号码牌数,再按放入顺序输出列表中的流水号,用一个空格分隔(为空时只输出 0)。

输入
1 ≤ m ≤ 100,1 ≤ q ≤ 5000,1 ≤ w ≤ m
输出
每个 take 和 show 命令输出一行
样例 1 · stdin
3 9
take 1
take 2
take 1
show 1
reset 1
show 1
take 1
show 1
show 3
stdout
1 1
2 1
3 2
2 1 3
0
4 1
1 4
0
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 6 种语言题解

本题只接受有类的 Python、JavaScript、TypeScript、Java、C#、C++(C 没有类,Craykon 还不能定义类)。
关键是区分"所有对象共用的值"和"每个对象各自的值"。
共用的流水号在 Java、C# 中是 static int,JS、TS 中是 static lastSerial = 0,C++ 中是 inline static int(C++17;没有 inline 就要在类外另写定义 int Window::lastSerial = 0;),Python 中是类体里的 last_serial = 0。
有三个陷阱。
Python 的 self.last_serial += 1 不会改变类变量,而是只在该对象上新建一个同名的值,于是每个窗口各自计数。
请用类名修改:Window.last_serial += 1。
反过来,把 served = [] 放在类体里,所有窗口就共用一个列表。
每个对象各自的列表要在 __init__ 中用 self.served = [] 创建。
JS 中用 this.lastSerial 读取静态字段会因为对象上没有它而得到 undefined,结果变成 NaN(TS 会用编译错误挡住)。
最后,创建 m 个对象时,Python 的 [Window()] * m 和 JS 的 Array(m).fill(new Window()) 让 m 个格子指向同一个对象。
请每格新建一个,如 Python [Window() for _ in range(m)]、JS Array.from({ length: m }, () => new Window())。
C++ 的 std::vector<Window> windows(m) 按值分别创建 m 个,没有问题。

Pythonmain.py · 35 行
import sys  class Window:    last_serial = 0  # 클래스 변수: 모든 창구가 하나를 함께 쓴다     def __init__(self):        self.served = []  # 객체마다 따로 갖는 목록(여기서 만들어야 한다)     def take(self):        Window.last_serial += 1  # self.last_serial += 1 이면 이 창구만의 값이 새로 생긴다        self.served.append(Window.last_serial)        return Window.last_serial, len(self.served)     def reset(self):        self.served = []     def show(self):        return " ".join(map(str, [len(self.served)] + self.served))  data = sys.stdin.read().split()m, q = int(data[0]), int(data[1])windows = [Window() for _ in range(m)]out = []for i in range(q):    cmd, w = data[2 + 2 * i], windows[int(data[3 + 2 * i]) - 1]    if cmd == "take":        serial, local = w.take()        out.append(f"{serial} {local}")    elif cmd == "reset":        w.reset()    else:        out.append(w.show())print("\n".join(out))
JavaScriptmain.js · 35 行
class Window {  static lastSerial = 0; // 정적 필드: 모든 창구가 하나를 함께 쓴다   constructor() {    this.served = []; // 객체마다 따로 갖는 목록  }   take() {    Window.lastSerial++; // this.lastSerial 은 객체에 없어서 undefined    this.served.push(Window.lastSerial);    return `${Window.lastSerial} ${this.served.length}`;  }   reset() {    this.served = [];  }   show() {    return [this.served.length, ...this.served].join(" ");  }} const data = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);const m = Number(data[0]);const q = Number(data[1]);const windows = Array.from({ length: m }, () => new Window());const out = [];for (let i = 0; i < q; i++) {  const cmd = data[2 + 2 * i];  const w = windows[Number(data[3 + 2 * i]) - 1];  if (cmd === "take") out.push(w.take());  else if (cmd === "reset") w.reset();  else out.push(w.show());}console.log(out.join("\n"));
TypeScriptmain.ts · 34 行
import { readFileSync } from "node:fs"; class Window {  private static lastSerial = 0; // 정적 필드: 모든 창구가 하나를 함께 쓴다  private served: number[] = []; // 객체마다 따로 갖는 목록   take(): string {    Window.lastSerial++;    this.served.push(Window.lastSerial);    return `${Window.lastSerial} ${this.served.length}`;  }   reset(): void {    this.served = [];  }   show(): string {    return [this.served.length, ...this.served].join(" ");  }} const data: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const m: number = Number(data[0]);const q: number = Number(data[1]);const windows: Window[] = Array.from({ length: m }, () => new Window());const out: string[] = [];for (let i = 0; i < q; i++) {  const cmd = data[2 + 2 * i];  const w = windows[Number(data[3 + 2 * i]) - 1];  if (cmd === "take") out.push(w.take());  else if (cmd === "reset") w.reset();  else out.push(w.show());}console.log(out.join("\n"));
JavaMain.java · 49 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import java.util.StringTokenizer; class Window {    private static int lastSerial = 0; // static: 모든 창구가 하나를 함께 쓴다    private List<Integer> served = new ArrayList<>(); // 객체마다 따로     String take() {        lastSerial++;        served.add(lastSerial);        return lastSerial + " " + served.size();    }     void reset() { served = new ArrayList<>(); }     String show() {        StringBuilder sb = new StringBuilder().append(served.size());        for (int s : served) sb.append(' ').append(s);        return sb.toString();    }} public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(in.readLine());        int m = Integer.parseInt(st.nextToken());        int q = Integer.parseInt(st.nextToken());        Window[] windows = new Window[m];        for (int i = 0; i < m; i++) windows[i] = new Window();         StringBuilder out = new StringBuilder();        for (int i = 0; i < q; i++) {            st = new StringTokenizer(in.readLine());            String cmd = st.nextToken();            Window w = windows[Integer.parseInt(st.nextToken()) - 1];            switch (cmd) {                case "take" -> out.append(w.take()).append('\n');                case "reset" -> w.reset();                default -> out.append(w.show()).append('\n');            }        }        System.out.print(out);    }}
C#Main.cs · 45 行
using System;using System.Collections.Generic;using System.Text; class Window{    private static int lastSerial = 0; // static: 모든 창구가 하나를 함께 쓴다    private List<int> served = new List<int>(); // 객체마다 따로     public string Take()    {        lastSerial++;        served.Add(lastSerial);        return $"{lastSerial} {served.Count}";    }     public void Reset() => served = new List<int>();     public string Show() => served.Count == 0 ? "0" : $"{served.Count} {string.Join(" ", served)}";} class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ');        int m = int.Parse(first[0]), q = int.Parse(first[1]);        var windows = new Window[m];        for (int i = 0; i < m; i++) windows[i] = new Window();         var sb = new StringBuilder();        for (int i = 0; i < q; i++)        {            string[] p = Console.ReadLine().Trim().Split(' ');            Window w = windows[int.Parse(p[1]) - 1];            switch (p[0])            {                case "take": sb.Append(w.Take()).Append('\n'); break;                case "reset": w.Reset(); break;                default: sb.Append(w.Show()).Append('\n'); break;            }        }        Console.Write(sb);    }}
C++main.cpp · 40 行
#include <iostream>#include <string>#include <vector> class Window {public:    std::string take() {        lastSerial++;        served_.push_back(lastSerial);        return std::to_string(lastSerial) + " " + std::to_string(served_.size());    }     void reset() { served_.clear(); }     std::string show() const {        std::string s = std::to_string(served_.size());        for (int x : served_) s += " " + std::to_string(x);        return s;    } private:    inline static int lastSerial = 0; // static: 모든 창구가 하나를 함께 쓴다(inline 없으면 클래스 밖에 정의가 필요)    std::vector<int> served_;          // 객체마다 따로}; int main() {    std::ios::sync_with_stdio(false);    int m, q;    std::cin >> m >> q;    std::vector<Window> windows(m); // 서로 다른 Window 객체 m개    for (int i = 0; i < q; i++) {        std::string cmd;        int w;        std::cin >> cmd >> w;        Window& win = windows[w - 1];        if (cmd == "take") std::cout << win.take() << '\n';        else if (cmd == "reset") win.reset();        else std::cout << win.show() << '\n';    }}