{ }codelper
methodsclassesP0323

Hourglasses that run together

There are n hourglasses, and hourglass i holds c_i grains of sand. At the start all the sand of every hourglass is in its bottom half. While time passes, every hourglass that has sand in its top half drops one grain per second from the top half to the bottom half, and once the top half is empty that hourglass stops. Make the hourglass a class with methods for 'flip', 'run for t seconds', 'is the top half empty?' and 'how many grains are left in the top half?', and process the following q commands in order. flip i: flip hourglass i (the numbers of grains in the top and bottom halves are exchanged).
Print nothing. wait t: t seconds pass for every hourglass.
Print the number of hourglasses whose top half became empty during these t seconds.
Hourglasses whose top half was already empty before the command are not counted. until i: as many seconds as there were grains in the top half of hourglass i just before the command pass for every hourglass alike (if the top half of hourglass i is already empty, no time passes).
Then print the total number of seconds that have passed through wait and until since the very beginning. flipdone: flip every hourglass whose top half is empty and print the number of hourglasses flipped. After all commands, for each hourglass from 1 to n print the number of grains in its top half and in its bottom half, separated by a single space, one hourglass per line.

Input
The first line has the number of hourglasses n and the number of commands q, separated by a single space.
The second line has c_1, …, c_n separated by single spaces.
Each of the next q lines has one command.
1 ≤ n ≤ 100, 1 ≤ q ≤ 1,000, 1 ≤ c_i ≤ 1,000,000, 1 ≤ t ≤ 1,000,000, 1 ≤ i ≤ n
Output
For each wait, until and flipdone command print its answer on its own line (digits only, no commas).
Then print n lines, one per hourglass, with the grains in the top half and in the bottom half separated by a single space
Example 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
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 · 6 languages

This problem takes only the languages with classes: Python, JavaScript, TypeScript, Java, C# and C++ (C has no classes, and Craykon cannot define classes yet).
A method is a function that reads or changes the values inside an object.
Python writes the first parameter self explicitly, as in def run(self, seconds):, and JS/TS reach the field as this.top inside run(seconds) { … }.
In Java, C# and C++ plain top already means the field.
C++ puts const after a method that changes nothing (bool isEmpty() const).
Flipping means exchanging two fields: Python self.top, self.bottom = self.bottom, self.top, JS/TS [this.top, this.bottom] = [this.bottom, this.top], C# (top, bottom) = (bottom, top) and C++ std::swap(top_, bottom_) do it in one line, while Java uses a temporary variable.
Six traps: ① Assigning one after the other, top = bottom; bottom = top;, loses the top value first, so both halves end up with the same number.
② Forgetting the parentheses when calling a method.
Python if g.is_empty: and JavaScript if (g.isEmpty) run without any error, but the method itself is always truthy, so even hourglasses that are not empty get flipped (the second flipdone of the example becomes 2 instead of 1).
TypeScript reports 'this condition will always return true' (TS2774), and Java, C# and C++ give a compile error.
If you want to write it without parentheses, make it a Python @property, a JS/TS get isEmpty() or a C# property bool IsEmpty => top == 0;.
③ Running must move only min(seconds, top) grains.
A plain top -= seconds makes the top half negative.
④ 'Became empty this time' is not the same as 'is empty now'.
If run returns top == 0, hourglasses that were empty all along are counted too (wait 5 in the example becomes 2 instead of 1).
⑤ In until, ask for the time once before the loop and keep it in a variable.
Asking again inside the loop, as in g.run(target.remaining()), gives 0 once hourglass i has emptied, so the hourglasses after it do not run.
⑥ C++ for (Hourglass g : glasses) copies each hourglass, so time passes for the copies.
Write Hourglass& g to change the real ones.
In Python, JS, TS, Java and C# the loop variable refers to the same object, so the change sticks.

Pythonmain.py · 65 lines
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 lines
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 lines
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 lines
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 lines
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 lines
#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';}