有 n 个沙漏,第 i 个沙漏里有 c_i 粒沙。 一开始每个沙漏的沙全部在下半部。 时间流逝时,上半部有沙的沙漏每秒有一粒沙从上半部落到下半部,上半部空了之后这个沙漏就不再流动。 把沙漏写成一个类,并把“翻转”“流动 t 秒”“询问上半部是否为空”“询问上半部剩余的沙数”写成方法,依次处理下面的 q 条命令。 flip i:把第 i 个沙漏翻转(上半部和下半部的沙数互换)。 不输出任何内容。 wait t:所有沙漏都经过 t 秒。 输出在这 t 秒内上半部变空的沙漏个数。 命令之前上半部就已经为空的沙漏不计入。 until i:所有沙漏同样经过若干秒,秒数等于命令执行前第 i 个沙漏上半部剩余的沙数(如果第 i 个沙漏的上半部已经为空,则时间不流逝)。 然后输出从最开始到现在通过 wait 和 until 流逝的时间总秒数。 flipdone:把上半部为空的沙漏全部翻转,并输出翻转的沙漏个数。 处理完所有命令后,从第 1 个到第 n 个,对每个沙漏输出一行:上半部的沙数和下半部的沙数,用一个空格隔开。
输入
第一行给出沙漏数 n 和命令数 q,用一个空格隔开。 第二行给出 c_1, …, c_n,用一个空格隔开。 接下来 q 行每行给出一条命令。 1 ≤ n ≤ 100,1 ≤ q ≤ 1,000,1 ≤ c_i ≤ 1,000,000,1 ≤ t ≤ 1,000,000,1 ≤ i ≤ n
输出
对每条 wait、until、flipdone 命令输出一行答案(只输出数字,不带逗号)。 之后输出 n 行,每行是一个沙漏上半部和下半部的沙数,用一个空格隔开
样例 1 · stdin
2 7
4 7
flipdone
until 1
flipdone
until 2
wait 5
flipdone
flip 2
stdout
2
4
1
7
1
2
4 0
0 7
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 6 种语言题解
这道题只接受有类的 Python、JavaScript、TypeScript、Java、C#、C++(C 没有类,Craykon 目前还不能定义类)。 方法是读取或修改对象内部的值的函数。 Python 要像 def run(self, seconds): 这样自己写出第一个参数 self,JS、TS 在 run(seconds) { … } 里用 this.top 访问字段。 Java、C#、C++ 直接写 top 就是字段。 C++ 在不修改值的方法后面加 const(bool isEmpty() const)。 翻转就是交换两个字段:Python self.top, self.bottom = self.bottom, self.top,JS、TS [this.top, this.bottom] = [this.bottom, this.top],C# (top, bottom) = (bottom, top),C++ std::swap(top_, bottom_) 都是一行,Java 则用一个临时变量。 六个陷阱:① 像 top = bottom; bottom = top; 这样依次赋值,上半部的值会先丢失,两部分变成同一个数。 ② 调用方法时漏掉括号。 Python 的 if g.is_empty: 和 JavaScript 的 if (g.isEmpty) 不报错也能运行,但方法本身永远为真,于是连不空的沙漏也被翻转(示例中第二个 flipdone 变成 2 而不是 1)。 TypeScript 会报“这个条件永远为真”的错误(TS2774),Java、C#、C++ 则报编译错误。 想不带括号使用,可以写成 Python @property、JS/TS get isEmpty()、C# 属性 bool IsEmpty => top == 0;。 ③ 流动时只能移动 min(seconds, top) 粒。 直接写 top -= seconds 会让上半部变成负数。 ④“这次变空了”和“现在是空的”不一样。 如果流动方法返回 top == 0,连原本就空的沙漏也会被计入(示例中的 wait 5 变成 2 而不是 1)。 ⑤ until 中要流动的时间在循环之前只问一次并存进变量。 在循环里像 g.run(target.remaining()) 这样重新询问,第 i 个沙漏变空之后就得到 0,编号在它后面的沙漏不会流动。 ⑥ C++ 的 for (Hourglass g : glasses) 会复制沙漏,时间流在副本上。 写成 Hourglass& g 才会改变真正的沙漏。 Python、JS、TS、Java、C# 的循环变量指向同一个对象,所以会直接改变。
Pythonmain.py · 65 行
import sysclass Hourglass: def __init__(self, capacity): # 처음에는 모래가 전부 아래 칸에 있다 self.top = 0 self.bottom = capacity def flip(self): self.top, self.bottom = self.bottom, self.top def run(self, seconds): """seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 True를 돌려준다.""" moved = min(seconds, self.top) self.top -= moved self.bottom += moved return moved > 0 and self.top == 0 def is_empty(self): return self.top == 0 def remaining(self): return self.topdef main(): lines = sys.stdin.read().split("\n") n, q = map(int, lines[0].split()) glasses = [Hourglass(int(c)) for c in lines[1].split()] elapsed = 0 out = [] for line in lines[2:2 + q]: parts = line.split() cmd = parts[0] if cmd == "flip": glasses[int(parts[1]) - 1].flip() elif cmd == "wait": t = int(parts[1]) elapsed += t done = 0 for g in glasses: if g.run(t): done += 1 out.append(str(done)) elif cmd == "until": # 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) t = glasses[int(parts[1]) - 1].remaining() elapsed += t for g in glasses: g.run(t) out.append(str(elapsed)) else: # flipdone flipped = 0 for g in glasses: if g.is_empty(): # 괄호를 빼면 메서드 자체라 늘 참이다 g.flip() flipped += 1 out.append(str(flipped)) for g in glasses: out.append(f"{g.top} {g.bottom}") print("\n".join(out))main()
JavaScriptmain.js · 64 行
class Hourglass { constructor(capacity) { // 처음에는 모래가 전부 아래 칸에 있다 this.top = 0; this.bottom = capacity; } flip() { [this.top, this.bottom] = [this.bottom, this.top]; } // seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 true를 돌려준다 run(seconds) { const moved = Math.min(seconds, this.top); this.top -= moved; this.bottom += moved; return moved > 0 && this.top === 0; } isEmpty() { return this.top === 0; } remaining() { return this.top; }}const lines = require("fs").readFileSync(0, "utf8").split("\n");const [n, q] = lines[0].trim().split(" ").map(Number);const glasses = lines[1].trim().split(" ").slice(0, n).map((c) => new Hourglass(Number(c)));let elapsed = 0;const out = [];for (let k = 2; k < 2 + q; k++) { const [cmd, arg] = lines[k].trim().split(" "); if (cmd === "flip") { glasses[Number(arg) - 1].flip(); } else if (cmd === "wait") { const t = Number(arg); elapsed += t; let done = 0; for (const g of glasses) { if (g.run(t)) done++; } out.push(done); } else if (cmd === "until") { // 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) const t = glasses[Number(arg) - 1].remaining(); elapsed += t; for (const g of glasses) g.run(t); out.push(elapsed); } else { let flipped = 0; for (const g of glasses) { if (g.isEmpty()) { // 괄호를 빼면 함수 자체라 늘 참이다 g.flip(); flipped++; } } out.push(flipped); }}for (const g of glasses) out.push(`${g.top} ${g.bottom}`);console.log(out.join("\n"));
TypeScriptmain.ts · 68 行
import { readFileSync } from "node:fs";class Hourglass { private top = 0; // 처음에는 모래가 전부 아래 칸에 있다 constructor(private bottom: number) {} flip(): void { [this.top, this.bottom] = [this.bottom, this.top]; } // seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 true를 돌려준다 run(seconds: number): boolean { const moved = Math.min(seconds, this.top); this.top -= moved; this.bottom += moved; return moved > 0 && this.top === 0; } isEmpty(): boolean { return this.top === 0; } remaining(): number { return this.top; } describe(): string { return `${this.top} ${this.bottom}`; }}const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, q] = lines[0].trim().split(" ").map(Number);const glasses: Hourglass[] = lines[1].trim().split(" ").slice(0, n).map((c) => new Hourglass(Number(c)));let elapsed = 0;const out: string[] = [];for (let k = 2; k < 2 + q; k++) { const [cmd, arg] = lines[k].trim().split(" "); if (cmd === "flip") { glasses[Number(arg) - 1].flip(); } else if (cmd === "wait") { const t = Number(arg); elapsed += t; let done = 0; for (const g of glasses) { if (g.run(t)) done++; } out.push(String(done)); } else if (cmd === "until") { // 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) const t = glasses[Number(arg) - 1].remaining(); elapsed += t; for (const g of glasses) g.run(t); out.push(String(elapsed)); } else { let flipped = 0; for (const g of glasses) { if (g.isEmpty()) { // 괄호를 빼면 TypeScript가 컴파일 오류로 알려 준다 g.flip(); flipped++; } } out.push(String(flipped)); }}for (const g of glasses) out.push(g.describe());console.log(out.join("\n"));
JavaMain.java · 83 行
import java.io.*;import java.util.*;public class Main { static class Hourglass { private int top = 0; // 처음에는 모래가 전부 아래 칸에 있다 private int bottom; Hourglass(int capacity) { this.bottom = capacity; } void flip() { int t = top; top = bottom; bottom = t; } // seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 true를 돌려준다 boolean run(int seconds) { int moved = Math.min(seconds, top); top -= moved; bottom += moved; return moved > 0 && top == 0; } boolean isEmpty() { return top == 0; } int remaining() { return top; } String describe() { return top + " " + bottom; } } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); int n = Integer.parseInt(st.nextToken()); int q = Integer.parseInt(st.nextToken()); st = new StringTokenizer(br.readLine()); Hourglass[] glasses = new Hourglass[n]; for (int i = 0; i < n; i++) glasses[i] = new Hourglass(Integer.parseInt(st.nextToken())); int elapsed = 0; StringBuilder sb = new StringBuilder(); for (int k = 0; k < q; k++) { st = new StringTokenizer(br.readLine()); String cmd = st.nextToken(); if (cmd.equals("flip")) { glasses[Integer.parseInt(st.nextToken()) - 1].flip(); } else if (cmd.equals("wait")) { int t = Integer.parseInt(st.nextToken()); elapsed += t; int done = 0; for (Hourglass g : glasses) { if (g.run(t)) done++; } sb.append(done).append('\n'); } else if (cmd.equals("until")) { // 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) int t = glasses[Integer.parseInt(st.nextToken()) - 1].remaining(); elapsed += t; for (Hourglass g : glasses) g.run(t); sb.append(elapsed).append('\n'); } else { int flipped = 0; for (Hourglass g : glasses) { if (g.isEmpty()) { g.flip(); flipped++; } } sb.append(flipped).append('\n'); } } for (Hourglass g : glasses) sb.append(g.describe()).append('\n'); System.out.print(sb); }}
C#Main.cs · 99 行
using System;using System.Linq;using System.Text;class Hourglass{ private int top = 0; // 처음에는 모래가 전부 아래 칸에 있다 private int bottom; public Hourglass(int capacity) { bottom = capacity; } public void Flip() { (top, bottom) = (bottom, top); } // seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 true를 돌려준다 public bool Run(int seconds) { int moved = Math.Min(seconds, top); top -= moved; bottom += moved; return moved > 0 && top == 0; } public bool IsEmpty() { return top == 0; } public int Remaining() { return top; } public string Describe() { return $"{top} {bottom}"; }}class Program{ static void Main() { int[] head = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); int q = head[1]; Hourglass[] glasses = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries) .Select(c => new Hourglass(int.Parse(c))).ToArray(); int elapsed = 0; var sb = new StringBuilder(); for (int k = 0; k < q; k++) { string[] parts = Console.ReadLine()!.Split(' ', StringSplitOptions.RemoveEmptyEntries); string cmd = parts[0]; if (cmd == "flip") { glasses[int.Parse(parts[1]) - 1].Flip(); } else if (cmd == "wait") { int t = int.Parse(parts[1]); elapsed += t; int done = 0; foreach (Hourglass g in glasses) { if (g.Run(t)) done++; } sb.Append(done).Append('\n'); } else if (cmd == "until") { // 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) int t = glasses[int.Parse(parts[1]) - 1].Remaining(); elapsed += t; foreach (Hourglass g in glasses) g.Run(t); sb.Append(elapsed).Append('\n'); } else { int flipped = 0; foreach (Hourglass g in glasses) { if (g.IsEmpty()) { g.Flip(); flipped++; } } sb.Append(flipped).Append('\n'); } } foreach (Hourglass g in glasses) sb.Append(g.Describe()).Append('\n'); Console.Write(sb); }}
C++main.cpp · 78 行
#include <algorithm>#include <iostream>#include <string>#include <utility>#include <vector>class Hourglass {public: explicit Hourglass(int capacity) : bottom_(capacity) {} void flip() { std::swap(top_, bottom_); } // seconds초가 흐른다. 이 동안 위 칸이 비게 되었으면 true를 돌려준다 bool run(int seconds) { int moved = std::min(seconds, top_); top_ -= moved; bottom_ += moved; return moved > 0 && top_ == 0; } // 값을 바꾸지 않는 메서드에는 const를 붙인다 bool isEmpty() const { return top_ == 0; } int remaining() const { return top_; } int bottom() const { return bottom_; }private: int top_ = 0; // 처음에는 모래가 전부 아래 칸에 있다 int bottom_;};int main() { std::ios::sync_with_stdio(false); int n, q; std::cin >> n >> q; std::vector<Hourglass> glasses; for (int i = 0; i < n; i++) { int c; std::cin >> c; glasses.emplace_back(c); } int elapsed = 0; for (int k = 0; k < q; k++) { std::string cmd; std::cin >> cmd; if (cmd == "flip") { int i; std::cin >> i; glasses[i - 1].flip(); } else if (cmd == "wait") { int t; std::cin >> t; elapsed += t; int done = 0; for (Hourglass& g : glasses) { // &가 없으면 복사본에 시간이 흐른다 if (g.run(t)) done++; } std::cout << done << '\n'; } else if (cmd == "until") { int i; std::cin >> i; // 흐를 시간은 반복 전에 한 번만 묻는다(반복 중에 물으면 i번이 비고 나서 0이 된다) int t = glasses[i - 1].remaining(); elapsed += t; for (Hourglass& g : glasses) g.run(t); std::cout << elapsed << '\n'; } else { int flipped = 0; for (Hourglass& g : glasses) { if (g.isEmpty()) { g.flip(); flipped++; } } std::cout << flipped << '\n'; } } for (const Hourglass& g : glasses) std::cout << g.remaining() << ' ' << g.bottom() << '\n';}