A home has n devices, and there are four kinds of device.
- Lamp (lamp): can be switched on and off. It uses 9 W when on and 0 W when off.
- Dimmable lamp (dimlamp): can be switched on and off and can also have its level set. It uses level × 2 W when on and 0 W when off.
- Fan (fan): can have its level set but cannot be switched on or off. It always uses level × 3 W.
- Sensor (sensor): can neither be switched nor have a level set. It always uses 1 W.
Devices that can be switched start off, and devices that can have a level set start at level 1.
A dimmable lamp's level can be changed even while it is off, and the changed level is used when it is switched on again.
Handle q commands in the given order, printing one line per command.
- power: print the total power all devices are using now.
- allon, alloff: switch on or off every device that can be switched. Print the number of devices whose state changed.
- alldim v: set every device that can have a level set to level v. Print the number of devices whose level changed.
- on name, off name: switch that device on or off.
- dim name v: set that device to level v.
A command with a name prints no if the device cannot do that, same if it can but was already in that state so nothing changed, and ok if it changed.
Make 'can be switched on and off' and 'can have a level set' two interfaces, and let each device class implement only what it can do.
Put all devices in one list, and handle the commands by asking only whether a device implements the interface, not what kind it is.
Input
The first line has n and q separated by one space. Each of the next n lines has a device's kind (one of lamp, dimlamp, fan, sensor) and its name separated by one space. Each of the next q lines has one command, with its words separated by single spaces. 1 ≤ n ≤ 100, 1 ≤ q ≤ 1000, 1 ≤ v ≤ 10. Names are 1 to 10 lowercase English letters or digits and are all different. Every name in a command is an existing device
Output
q lines. One line per command: a single number, or one of ok, same, no
Example 1 · stdin
4 12
lamp desk
dimlamp bed
fan air
sensor door
power
allon
dim desk 4
alldim 4
on air
power
alloff
dim bed 7
on bed
on bed
allon
power
stdout
4
2
no
2
no
30
2
ok
ok
same
1
36
main.py
Error List00F8 ↓ · ⇧F8 ↑
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 · 5 languages
This problem accepts only Python, TypeScript, Java, C# and C++, which have interfaces or syntax that plays that role. JavaScript has nowhere to write an interface, and C and Craykon have no classes. The points are that one class can implement several interfaces, and how you ask at run time whether an object implements an interface. Java writes class DimLamp extends Device implements Switchable, Dimmable and asks with d instanceof Switchable s, which also binds s. C# writes class DimLamp : Device, ISwitchable, IDimmable and d is ISwitchable s. C++ inherits from several structs that have only pure virtual functions and checks whether dynamic_cast<Switchable*>(d) is nullptr. Python inherits from several abc.ABC classes and asks with isinstance(d, Switchable). TypeScript interfaces vanish from the running code, so writing d instanceof Switchable is a type error (TS2693). The solution therefore has type-guard functions that check for the method with "turn" in d and return d is Device & Switchable. Trap one: asking for the concrete class instead of the interface (dynamic_cast<Lamp*>) leaves out the dimmable lamp. In the example allon becomes 1 and on bed becomes no. Trap two: converting without asking also behaves differently by language. Java's (Dimmable) d is checked at run time and stops with ClassCastException at dim desk 4 in the example. TypeScript's as Device & Dimmable checks nothing at run time, so the same line fails with TypeError: d.setLevel is not a function. Trap three: in Python, if you write the interfaces as typing.Protocol, isinstance raises TypeError unless you add @runtime_checkable (it stops at allon in the example). Trap four: allon reports the number of devices whose state changed, not the number that can be switched. Counting every switchable device turns the last allon of the example into 2 instead of 1. That is why the interface methods return whether something changed. Trap five: if you do not change the level of a dimmable lamp that is off, dim bed 7 in the example becomes same and the last power becomes 30.
Pythonmain.py · 118 lines
import sysfrom abc import ABC, abstractmethodclass Device(ABC): def __init__(self, name: str): self.name = name @abstractmethod def power(self) -> int: ...class Switchable(ABC): """켜고 끌 수 있다. 상태가 바뀌었으면 True를 돌려준다""" @abstractmethod def turn(self, on: bool) -> bool: ...class Dimmable(ABC): """단계를 정할 수 있다. 단계가 바뀌었으면 True를 돌려준다""" @abstractmethod def set_level(self, v: int) -> bool: ...class Lamp(Device, Switchable): def __init__(self, name: str): super().__init__(name) self.on = False def turn(self, on: bool) -> bool: changed = self.on != on self.on = on return changed def power(self) -> int: return 9 if self.on else 0class DimLamp(Device, Switchable, Dimmable): def __init__(self, name: str): super().__init__(name) self.on = False self.level = 1 def turn(self, on: bool) -> bool: changed = self.on != on self.on = on return changed def set_level(self, v: int) -> bool: # 꺼져 있어도 단계는 바뀐다 changed = self.level != v self.level = v return changed def power(self) -> int: return 2 * self.level if self.on else 0class Fan(Device, Dimmable): def __init__(self, name: str): super().__init__(name) self.level = 1 def set_level(self, v: int) -> bool: changed = self.level != v self.level = v return changed def power(self) -> int: return 3 * self.levelclass Sensor(Device): def power(self) -> int: return 1KINDS = {"lamp": Lamp, "dimlamp": DimLamp, "fan": Fan, "sensor": Sensor}def word(changed: bool) -> str: return "ok" if changed else "same"def main() -> None: lines = sys.stdin.read().split("\n") n, q = map(int, lines[0].split()) devices: list[Device] = [] by_name: dict[str, Device] = {} for i in range(1, n + 1): kind, name = lines[i].split() d = KINDS[kind](name) devices.append(d) by_name[name] = d out = [] for i in range(n + 1, n + 1 + q): p = lines[i].split() cmd = p[0] if cmd == "power": out.append(str(sum(d.power() for d in devices))) elif cmd in ("allon", "alloff"): out.append(str(sum(1 for d in devices if isinstance(d, Switchable) and d.turn(cmd == "allon")))) elif cmd == "alldim": v = int(p[1]) out.append(str(sum(1 for d in devices if isinstance(d, Dimmable) and d.set_level(v)))) elif cmd in ("on", "off"): d = by_name[p[1]] out.append(word(d.turn(cmd == "on")) if isinstance(d, Switchable) else "no") else: # dim 이름 v d = by_name[p[1]] out.append(word(d.set_level(int(p[2]))) if isinstance(d, Dimmable) else "no") print("\n".join(out))main()
TypeScriptmain.ts · 120 lines
import { readFileSync } from "node:fs";// 켜고 끌 수 있다. 상태가 바뀌었으면 true를 돌려준다interface Switchable { turn(on: boolean): boolean;}// 단계를 정할 수 있다. 단계가 바뀌었으면 true를 돌려준다interface Dimmable { setLevel(v: number): boolean;}abstract class Device { constructor(readonly name: string) {} abstract power(): number;}class Lamp extends Device implements Switchable { private on = false; turn(on: boolean): boolean { const changed = this.on !== on; this.on = on; return changed; } power(): number { return this.on ? 9 : 0; }}class DimLamp extends Device implements Switchable, Dimmable { private on = false; private level = 1; turn(on: boolean): boolean { const changed = this.on !== on; this.on = on; return changed; } setLevel(v: number): boolean { // 꺼져 있어도 단계는 바뀐다 const changed = this.level !== v; this.level = v; return changed; } power(): number { return this.on ? 2 * this.level : 0; }}class Fan extends Device implements Dimmable { private level = 1; setLevel(v: number): boolean { const changed = this.level !== v; this.level = v; return changed; } power(): number { return 3 * this.level; }}class Sensor extends Device { power(): number { return 1; }}// 인터페이스는 실행할 때 없으므로, 메서드가 있는지를 보고 타입을 좁혀 주는 함수를 만든다function isSwitchable(d: Device): d is Device & Switchable { return "turn" in d;}function isDimmable(d: Device): d is Device & Dimmable { return "setLevel" in d;}function make(kind: string, name: string): Device { if (kind === "lamp") return new Lamp(name); if (kind === "dimlamp") return new DimLamp(name); if (kind === "fan") return new Fan(name); return new Sensor(name);}const word = (changed: boolean): string => (changed ? "ok" : "same");const lines: string[] = readFileSync(0, "utf8").split("\n");const [n, q] = lines[0].trim().split(/\s+/).map(Number);const devices: Device[] = [];const byName = new Map<string, Device>();for (let i = 1; i <= n; i++) { const [kind, name] = lines[i].trim().split(/\s+/); const d = make(kind, name); devices.push(d); byName.set(name, d);}const out: string[] = [];for (let i = n + 1; i <= n + q; i++) { const p = lines[i].trim().split(/\s+/); const cmd = p[0]; if (cmd === "power") { let total = 0; for (const d of devices) total += d.power(); out.push(String(total)); } else if (cmd === "allon" || cmd === "alloff") { let count = 0; for (const d of devices) if (isSwitchable(d) && d.turn(cmd === "allon")) count++; out.push(String(count)); } else if (cmd === "alldim") { const v = Number(p[1]); let count = 0; for (const d of devices) if (isDimmable(d) && d.setLevel(v)) count++; out.push(String(count)); } else if (cmd === "on" || cmd === "off") { const d = byName.get(p[1])!; out.push(isSwitchable(d) ? word(d.turn(cmd === "on")) : "no"); } else { const d = byName.get(p[1])!; out.push(isDimmable(d) ? word(d.setLevel(Number(p[2]))) : "no"); }}console.log(out.join("\n"));
JavaMain.java · 121 lines
import java.io.*;import java.util.*;// 켜고 끌 수 있다. 상태가 바뀌었으면 true를 돌려준다interface Switchable { boolean turn(boolean on);}// 단계를 정할 수 있다. 단계가 바뀌었으면 true를 돌려준다interface Dimmable { boolean setLevel(int v);}abstract class Device { final String name; Device(String name) { this.name = name; } abstract int power();}class Lamp extends Device implements Switchable { private boolean on = false; Lamp(String name) { super(name); } public boolean turn(boolean on) { boolean changed = this.on != on; this.on = on; return changed; } int power() { return on ? 9 : 0; }}class DimLamp extends Device implements Switchable, Dimmable { private boolean on = false; private int level = 1; DimLamp(String name) { super(name); } public boolean turn(boolean on) { boolean changed = this.on != on; this.on = on; return changed; } public boolean setLevel(int v) { // 꺼져 있어도 단계는 바뀐다 boolean changed = level != v; level = v; return changed; } int power() { return on ? 2 * level : 0; }}class Fan extends Device implements Dimmable { private int level = 1; Fan(String name) { super(name); } public boolean setLevel(int v) { boolean changed = level != v; level = v; return changed; } int power() { return 3 * level; }}class Sensor extends Device { Sensor(String name) { super(name); } int power() { return 1; }}public class Main { static Device make(String kind, String name) { switch (kind) { case "lamp": return new Lamp(name); case "dimlamp": return new DimLamp(name); case "fan": return new Fan(name); default: return new Sensor(name); } } static String word(boolean changed) { return changed ? "ok" : "same"; } 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()), q = Integer.parseInt(st.nextToken()); List<Device> devices = new ArrayList<>(); Map<String, Device> byName = new HashMap<>(); for (int i = 0; i < n; i++) { st = new StringTokenizer(br.readLine()); String kind = st.nextToken(), name = st.nextToken(); Device d = make(kind, name); devices.add(d); byName.put(name, d); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < q; i++) { st = new StringTokenizer(br.readLine()); String cmd = st.nextToken(); if (cmd.equals("power")) { int total = 0; for (Device d : devices) total += d.power(); sb.append(total); } else if (cmd.equals("allon") || cmd.equals("alloff")) { int count = 0; for (Device d : devices) if (d instanceof Switchable s && s.turn(cmd.equals("allon"))) count++; sb.append(count); } else if (cmd.equals("alldim")) { int v = Integer.parseInt(st.nextToken()); int count = 0; for (Device d : devices) if (d instanceof Dimmable m && m.setLevel(v)) count++; sb.append(count); } else if (cmd.equals("on") || cmd.equals("off")) { Device d = byName.get(st.nextToken()); sb.append(d instanceof Switchable s ? word(s.turn(cmd.equals("on"))) : "no"); } else { Device d = byName.get(st.nextToken()); int v = Integer.parseInt(st.nextToken()); sb.append(d instanceof Dimmable m ? word(m.setLevel(v)) : "no"); } sb.append('\n'); } System.out.print(sb); }}
C#Main.cs · 146 lines
using System;using System.Collections.Generic;using System.Text;// 켜고 끌 수 있다. 상태가 바뀌었으면 true를 돌려준다interface ISwitchable{ bool Turn(bool on);}// 단계를 정할 수 있다. 단계가 바뀌었으면 true를 돌려준다interface IDimmable{ bool SetLevel(int v);}abstract class Device{ public string Name { get; } protected Device(string name) { Name = name; } public abstract int Power();}class Lamp : Device, ISwitchable{ private bool on = false; public Lamp(string name) : base(name) { } public bool Turn(bool on) { bool changed = this.on != on; this.on = on; return changed; } public override int Power() => on ? 9 : 0;}class DimLamp : Device, ISwitchable, IDimmable{ private bool on = false; private int level = 1; public DimLamp(string name) : base(name) { } public bool Turn(bool on) { bool changed = this.on != on; this.on = on; return changed; } public bool SetLevel(int v) // 꺼져 있어도 단계는 바뀐다 { bool changed = level != v; level = v; return changed; } public override int Power() => on ? 2 * level : 0;}class Fan : Device, IDimmable{ private int level = 1; public Fan(string name) : base(name) { } public bool SetLevel(int v) { bool changed = level != v; level = v; return changed; } public override int Power() => 3 * level;}class Sensor : Device{ public Sensor(string name) : base(name) { } public override int Power() => 1;}class Program{ static Device Make(string kind, string name) { switch (kind) { case "lamp": return new Lamp(name); case "dimlamp": return new DimLamp(name); case "fan": return new Fan(name); default: return new Sensor(name); } } static string Word(bool changed) => changed ? "ok" : "same"; static void Main() { var lines = Console.In.ReadToEnd().Split('\n'); var first = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries); int n = int.Parse(first[0]), q = int.Parse(first[1]); var devices = new List<Device>(); var byName = new Dictionary<string, Device>(); for (int i = 1; i <= n; i++) { var p = lines[i].Trim().Split(' '); Device d = Make(p[0], p[1]); devices.Add(d); byName[p[1]] = d; } var sb = new StringBuilder(); for (int i = n + 1; i <= n + q; i++) { var p = lines[i].Trim().Split(' '); string cmd = p[0]; if (cmd == "power") { int total = 0; foreach (Device d in devices) total += d.Power(); sb.Append(total); } else if (cmd == "allon" || cmd == "alloff") { int count = 0; foreach (Device d in devices) if (d is ISwitchable s && s.Turn(cmd == "allon")) count++; sb.Append(count); } else if (cmd == "alldim") { int v = int.Parse(p[1]); int count = 0; foreach (Device d in devices) if (d is IDimmable m && m.SetLevel(v)) count++; sb.Append(count); } else if (cmd == "on" || cmd == "off") { Device d = byName[p[1]]; sb.Append(d is ISwitchable s ? Word(s.Turn(cmd == "on")) : "no"); } else { Device d = byName[p[1]]; sb.Append(d is IDimmable m ? Word(m.SetLevel(int.Parse(p[2]))) : "no"); } sb.Append('\n'); } Console.Write(sb); }}
C++main.cpp · 129 lines
#include <iostream>#include <map>#include <memory>#include <string>#include <vector>using namespace std;// 켜고 끌 수 있다. 상태가 바뀌었으면 true를 돌려준다struct Switchable { virtual bool turn(bool on) = 0; virtual ~Switchable() = default;};// 단계를 정할 수 있다. 단계가 바뀌었으면 true를 돌려준다struct Dimmable { virtual bool setLevel(int v) = 0; virtual ~Dimmable() = default;};struct Device { string name; explicit Device(string name) : name(std::move(name)) {} virtual int power() const = 0; virtual ~Device() = default; // 가상 함수가 있어야 dynamic_cast를 쓸 수 있다};class Lamp : public Device, public Switchable { bool on_ = false;public: using Device::Device; bool turn(bool on) override { bool changed = on_ != on; on_ = on; return changed; } int power() const override { return on_ ? 9 : 0; }};class DimLamp : public Device, public Switchable, public Dimmable { bool on_ = false; int level_ = 1;public: using Device::Device; bool turn(bool on) override { bool changed = on_ != on; on_ = on; return changed; } bool setLevel(int v) override { // 꺼져 있어도 단계는 바뀐다 bool changed = level_ != v; level_ = v; return changed; } int power() const override { return on_ ? 2 * level_ : 0; }};class Fan : public Device, public Dimmable { int level_ = 1;public: using Device::Device; bool setLevel(int v) override { bool changed = level_ != v; level_ = v; return changed; } int power() const override { return 3 * level_; }};class Sensor : public Device {public: using Device::Device; int power() const override { return 1; }};unique_ptr<Device> make(const string& kind, const string& name) { if (kind == "lamp") return make_unique<Lamp>(name); if (kind == "dimlamp") return make_unique<DimLamp>(name); if (kind == "fan") return make_unique<Fan>(name); return make_unique<Sensor>(name);}const char* word(bool changed) { return changed ? "ok" : "same"; }int main() { int n, q; cin >> n >> q; vector<unique_ptr<Device>> devices; map<string, Device*> byName; for (int i = 0; i < n; i++) { string kind, name; cin >> kind >> name; devices.push_back(make(kind, name)); byName[name] = devices.back().get(); } for (int i = 0; i < q; i++) { string cmd; cin >> cmd; if (cmd == "power") { int total = 0; for (const auto& d : devices) total += d->power(); cout << total << '\n'; } else if (cmd == "allon" || cmd == "alloff") { int count = 0; for (const auto& d : devices) if (auto* s = dynamic_cast<Switchable*>(d.get()); s && s->turn(cmd == "allon")) count++; cout << count << '\n'; } else if (cmd == "alldim") { int v; cin >> v; int count = 0; for (const auto& d : devices) if (auto* m = dynamic_cast<Dimmable*>(d.get()); m && m->setLevel(v)) count++; cout << count << '\n'; } else if (cmd == "on" || cmd == "off") { string name; cin >> name; auto* s = dynamic_cast<Switchable*>(byName[name]); cout << (s ? word(s->turn(cmd == "on")) : "no") << '\n'; } else { string name; int v; cin >> name >> v; auto* m = dynamic_cast<Dimmable*>(byName[name]); cout << (m ? word(m->setLevel(v)) : "no") << '\n'; } } return 0;}