An online shop has n orders, numbered 1 to n, and all of them start in the CREATED state.
An order's state is one of seven: CREATED, PAID, SHIPPED, DELIVERED, CANCELLED, REFUNDED, RETURNED.
There are five events: pay, ship, deliver, cancel, return, and the state changes only in the following six cases.
- CREATED with pay → PAID
- CREATED with cancel → CANCELLED
- PAID with ship → SHIPPED
- PAID with cancel → REFUNDED
- SHIPPED with deliver → DELIVERED
- DELIVERED with return → RETURNED
Every other (state, event) pair is rejected, and that order's state stays the same.
CANCELLED, REFUNDED and RETURNED accept no events at all.
The first line gives n and the number of events q, and the next q lines give "order event" in the order they happen.
Print the final state of orders 1 to n, one per line, as its upper-case name, and on the last line print the number of rejected events.
Try modeling the state as an enum with seven values, and writing the state machine as one function that takes the current state and an event and decides the next state.
Input
1 ≤ n ≤ 1,000, 1 ≤ q ≤ 10,000, 1 ≤ order ≤ n, each event is one of pay, ship, deliver, cancel, return
Output
n+1 lines: the state name of each order, then the number of rejected events
Example 1 · stdin
3 6
1 pay
1 ship
2 cancel
2 pay
3 pay
3 cancel
stdout
SHIPPED
CANCELLED
REFUNDED
1
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 · 6 languages
This problem accepts only Python, TypeScript, Java, C#, C and C++, the languages that have enums. JavaScript has no enum syntax (you can only imitate one with Object.freeze({...})), and Craykon has no enums either. Printing a state's name differs by language. For a Python class State(Enum) value, s.name is "PAID", while print(s) prints State.PAID. A TypeScript numeric enum has the values 0, 1, 2…, so console.log(s) prints 1; you get the name from the reverse mapping State[s]. A Java enum is a class whose toString() is the name, and a switch expression does not compile unless it covers every constant. A C# enum's ToString() is the declared name as written (Paid), so this solution uses ToUpperInvariant(), and a tuple pattern (s, ev) switch { (State.Paid, "cancel") => ... } matches state and event at once. A C enum is just named int constants, so you keep a separate name table NAME[s]; a C++ enum class doesn't know its names either, so a switch returns them. Four traps: ① In a C or C++ switch, a missing break lets a ship that CREATED doesn't accept fall through into the PAID case and become SHIPPED. ② Printing the enum value itself, as in print(s) (Python) or console.log(s) (TypeScript), gives State.PAID or 1 instead of the name. ③ cancel depends on the state: CANCELLED from CREATED, REFUNDED from PAID, rejected otherwise. Writing it as one line that ignores the state, like (_, "cancel") => Cancelled, is wrong. ④ In Java, comparing the event string with event == "pay" is always false, because the string you read and the literal are different objects. Compare with equals.
Pythonmain.py · 38 lines
import sysfrom enum import Enumclass State(Enum): CREATED = 1 PAID = 2 SHIPPED = 3 DELIVERED = 4 CANCELLED = 5 REFUNDED = 6 RETURNED = 7# 상태 기계: (지금 상태, 사건) → 다음 상태. 표에 없는 짝은 거절NEXT = { (State.CREATED, "pay"): State.PAID, (State.CREATED, "cancel"): State.CANCELLED, (State.PAID, "ship"): State.SHIPPED, (State.PAID, "cancel"): State.REFUNDED, (State.SHIPPED, "deliver"): State.DELIVERED, (State.DELIVERED, "return"): State.RETURNED,}data = sys.stdin.read().split()n, q = int(data[0]), int(data[1])orders = [State.CREATED] * nrejected = 0for i in range(q): k, event = int(data[2 + 2 * i]) - 1, data[3 + 2 * i] nxt = NEXT.get((orders[k], event)) if nxt is None: rejected += 1 else: orders[k] = nxtprint("\n".join(s.name for s in orders)) # print(s)는 "State.PAID"를 찍는다print(rejected)
TypeScriptmain.ts · 43 lines
import { readFileSync } from "node:fs";enum State { CREATED, PAID, SHIPPED, DELIVERED, CANCELLED, REFUNDED, RETURNED,}// 상태 기계: 받을 수 없는 사건이면 nullfunction next(s: State, event: string): State | null { switch (s) { case State.CREATED: return event === "pay" ? State.PAID : event === "cancel" ? State.CANCELLED : null; case State.PAID: return event === "ship" ? State.SHIPPED : event === "cancel" ? State.REFUNDED : null; case State.SHIPPED: return event === "deliver" ? State.DELIVERED : null; case State.DELIVERED: return event === "return" ? State.RETURNED : null; default: return null; // CANCELLED·REFUNDED·RETURNED는 끝 상태 }}const words: string[] = readFileSync(0, "utf8").trim().split(/\s+/);const n = Number(words[0]);const q = Number(words[1]);const orders: State[] = new Array<State>(n).fill(State.CREATED);let rejected = 0;for (let i = 0; i < q; i++) { const k = Number(words[2 + 2 * i]) - 1; const ns = next(orders[k], words[3 + 2 * i]); if (ns === null) rejected++; else orders[k] = ns;}// 숫자 enum의 값은 0, 1, 2…: 이름은 역방향 표 State[s]로 꺼낸다console.log(orders.map((s) => State[s]).join("\n"));console.log(rejected);
JavaMain.java · 37 lines
import java.io.*;import java.util.*;public class Main { enum State { CREATED, PAID, SHIPPED, DELIVERED, CANCELLED, REFUNDED, RETURNED } // 상태 기계: 받을 수 없는 사건이면 null static State next(State s, String event) { return switch (s) { case CREATED -> event.equals("pay") ? State.PAID : event.equals("cancel") ? State.CANCELLED : null; case PAID -> event.equals("ship") ? State.SHIPPED : event.equals("cancel") ? State.REFUNDED : null; case SHIPPED -> event.equals("deliver") ? State.DELIVERED : null; case DELIVERED -> event.equals("return") ? State.RETURNED : null; case CANCELLED, REFUNDED, RETURNED -> null; // 끝 상태 }; } 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()); State[] orders = new State[n]; Arrays.fill(orders, State.CREATED); int rejected = 0; for (int i = 0; i < q; i++) { st = new StringTokenizer(br.readLine()); int k = Integer.parseInt(st.nextToken()) - 1; State ns = next(orders[k], st.nextToken()); if (ns == null) rejected++; else orders[k] = ns; } StringBuilder sb = new StringBuilder(); for (State s : orders) sb.append(s).append('\n'); // enum의 toString()은 이름 sb.append(rejected).append('\n'); System.out.print(sb); }}
C#Main.cs · 40 lines
using System;using System.Linq;using System.Text;enum State { Created, Paid, Shipped, Delivered, Cancelled, Refunded, Returned }class Program{ // 상태 기계: (상태, 사건) 튜플 패턴. 받을 수 없는 사건이면 null static State? Next(State s, string ev) => (s, ev) switch { (State.Created, "pay") => State.Paid, (State.Created, "cancel") => State.Cancelled, (State.Paid, "ship") => State.Shipped, (State.Paid, "cancel") => State.Refunded, (State.Shipped, "deliver") => State.Delivered, (State.Delivered, "return") => State.Returned, _ => null, }; static void Main() { var first = Console.ReadLine()!.Split(' '); int n = int.Parse(first[0]), q = int.Parse(first[1]); var orders = Enumerable.Repeat(State.Created, n).ToArray(); int rejected = 0; for (int i = 0; i < q; i++) { var p = Console.ReadLine()!.Split(' '); int k = int.Parse(p[0]) - 1; State? ns = Next(orders[k], p[1]); if (ns is State s) orders[k] = s; else rejected++; } var sb = new StringBuilder(); foreach (var s in orders) sb.Append(s.ToString().ToUpperInvariant()).Append('\n'); // ToString()은 "Paid" sb.Append(rejected).Append('\n'); Console.Write(sb); }}
C++main.cpp · 60 lines
#include <iostream>#include <optional>#include <string>#include <vector>enum class State { Created, Paid, Shipped, Delivered, Cancelled, Refunded, Returned };// enum class도 이름을 모른다: switch로 이름표를 만든다const char *name(State s) { switch (s) { case State::Created: return "CREATED"; case State::Paid: return "PAID"; case State::Shipped: return "SHIPPED"; case State::Delivered: return "DELIVERED"; case State::Cancelled: return "CANCELLED"; case State::Refunded: return "REFUNDED"; case State::Returned: return "RETURNED"; } return "?";}// 상태 기계: 받을 수 없는 사건이면 빈 optionalstd::optional<State> next(State s, const std::string &ev) { switch (s) { case State::Created: if (ev == "pay") return State::Paid; if (ev == "cancel") return State::Cancelled; break; case State::Paid: if (ev == "ship") return State::Shipped; if (ev == "cancel") return State::Refunded; break; case State::Shipped: if (ev == "deliver") return State::Delivered; break; case State::Delivered: if (ev == "return") return State::Returned; break; default: break; // 끝 상태 } return std::nullopt;}int main() { std::ios::sync_with_stdio(false); int n, q; std::cin >> n >> q; std::vector<State> orders(n, State::Created); int rejected = 0; for (int i = 0; i < q; i++) { int k; std::string ev; std::cin >> k >> ev; if (auto ns = next(orders[k - 1], ev)) orders[k - 1] = *ns; else rejected++; } for (State s : orders) std::cout << name(s) << '\n'; std::cout << rejected << '\n';}
Cmain.c · 46 lines
#include <stdio.h>#include <string.h>enum State { CREATED, PAID, SHIPPED, DELIVERED, CANCELLED, REFUNDED, RETURNED };/* C 열거형은 이름 붙은 int일 뿐이라 이름표를 따로 둔다(차례가 enum과 같아야 한다) */static const char *NAME[] = { "CREATED", "PAID", "SHIPPED", "DELIVERED", "CANCELLED", "REFUNDED", "RETURNED" };/* 다음 상태를 *s에 쓰고 1, 받을 수 없는 사건이면 0 */int step(enum State *s, const char *ev) { switch (*s) { case CREATED: if (strcmp(ev, "pay") == 0) { *s = PAID; return 1; } if (strcmp(ev, "cancel") == 0) { *s = CANCELLED; return 1; } break; /* break가 없으면 아래 case로 흘러내린다 */ case PAID: if (strcmp(ev, "ship") == 0) { *s = SHIPPED; return 1; } if (strcmp(ev, "cancel") == 0) { *s = REFUNDED; return 1; } break; case SHIPPED: if (strcmp(ev, "deliver") == 0) { *s = DELIVERED; return 1; } break; case DELIVERED: if (strcmp(ev, "return") == 0) { *s = RETURNED; return 1; } break; default: /* 끝 상태 */ break; } return 0;}int main(void) { static enum State orders[1000]; int n, q, rejected = 0; scanf("%d %d", &n, &q); for (int i = 0; i < n; i++) orders[i] = CREATED; for (int i = 0; i < q; i++) { int k; char ev[16]; scanf("%d %15s", &k, ev); if (!step(&orders[k - 1], ev)) rejected++; } for (int i = 0; i < n; i++) puts(NAME[orders[i]]); printf("%d\n", rejected); return 0;}