{ }codelper
메서드클래스P0323

함께 흐르는 모래시계

모래시계 n개가 있고, i번 모래시계에는 모래가 c_i알 들어 있다. 처음에는 모든 모래시계의 모래가 전부 아래 칸에 있다. 시간이 흐르면 위 칸에 모래가 있는 모래시계마다 1초에 한 알씩 위 칸에서 아래 칸으로 떨어지고, 위 칸이 비면 그 모래시계는 더 흐르지 않는다. 모래시계를 클래스로 만들고, '뒤집기', '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
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 6개 언어 풀이

이 문제는 클래스가 있는 Python·JavaScript·TypeScript·Java·C#·C++만 받아요(C에는 클래스가 없고, 크레이콘은 아직 클래스를 만들 수 없어요).
메서드는 객체 안의 값을 읽거나 바꾸는 함수예요.
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이 1이 아니라 2가 돼요).
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가 1이 아니라 2가 돼요).
⑤ until에서 흐를 시간은 반복 전에 한 번만 물어 변수에 담아요.
반복 안에서 g.run(target.remaining())처럼 다시 물으면 i번이 비고 나서는 0이 되어 뒤 번호 모래시계는 흐르지 않아요.
⑥ C++의 for (Hourglass g : glasses)는 모래시계를 복사해서 복사본에 시간이 흘러요.
Hourglass& g라 써야 진짜가 바뀌어요.
Python·JS·TS·Java·C#의 반복 변수는 같은 객체를 가리키니 그대로 바뀌어요.

Pythonmain.py · 65 줄
import sys  class 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.top  def 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';}