작은 계산기에 영어 소문자 a부터 z까지 이름이 붙은 칸 26개가 있다. 모든 칸은 처음에 0이다.
첫 줄에 명령 수 q가, 다음 q줄에 명령이 하나씩 주어진다. 명령 안의 낱말은 빈칸 하나로 나뉜다.
set x v는 칸 x에 정수 v를 넣는다.
swap x y는 칸 x와 칸 y의 값을 맞바꾼다. x와 y는 같을 수 있고, 그때는 아무것도 바뀌지 않는다.
rot x y z는 서로 다른 세 칸의 값을 돌린다. x는 y의 원래 값을, y는 z의 원래 값을, z는 x의 원래 값을 받는다.
let x1 x2 … xk = e1 e2 … ek는 칸 xi에 항 ei의 값을 넣는다(i = 1, …, k). 왼쪽 칸 이름들은 서로 다르다.
이때 오른쪽의 항 k개를 모두 이 명령 직전의 값으로 먼저 계산하고, 그다음에 k칸에 한꺼번에 넣는다.
항은 칸 이름 하나, 0 이상의 정수 하나, 또는 u+w나 u-w 꼴이다. u와 w는 각각 칸 이름이거나 0 이상의 정수이고, 사이에 빈칸이 없다.
show x1 x2 … xk는 칸 x1, x2, …, xk의 값을 이 차례대로 빈칸 하나씩 띄어 한 줄에 출력한다. 같은 칸이 여러 번 나올 수도 있다.
명령을 차례대로 처리하며 show마다 한 줄씩 출력하라.
입력
1 ≤ q ≤ 2,000. set의 v는 -1,000,000 이상 1,000,000 이하. 항 안의 정수는 0 이상 1,000,000 이하. let과 show의 칸 수 k는 1 이상 26 이하. show는 1개 이상 200개 이하. 모든 칸의 값은 언제나 -1,000,000,000 이상 1,000,000,000 이하다
출력
show 수만큼의 줄
예시 1 · stdin
7
set a 1
let a b = a+b a
let a b = a+b a
let a b = a+b a
show a b
swap a b
show a b
stdout
3 2
2 3
예시 2 · stdin
9
set x 5
set y -7
set z 9
swap x x
show x
rot x y z
show x y z
let x y z = z-1 x+y 100
show x y z
stdout
5
-7 9 5
4 2 100
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
두 값을 맞바꾸는 방법이 언어마다 달라요. Python a, b = b, a, JS·TS [a, b] = [b, a], C# (a, b) = (b, a)처럼 한꺼번에 넣는 문법이 있으면 오른쪽을 모두 계산한 뒤에 넣어서 rot도 한 줄이에요. C++은 문법 대신 std::swap(a, b) 함수가 있고, Java·C·크레이콘은 임시 변수 tmp에 하나를 맡겨 둬요. let은 칸 수 k가 그때그때 달라서 어느 언어든 오른쪽 값을 먼저 배열(Python·크레이콘은 목록)에 모은 뒤 넣어요. 함정 ① let을 하나씩 계산하자마자 넣기: let a b = a+b a에서 a를 먼저 바꾸면 b는 새 a를 받아요. ② 복사가 아닌 이름 붙이기: Python old = reg, JS const old = reg는 같은 사전·배열을 가리켜서 미리 찍어 둔 것이 되지 않아요. dict(reg), [...reg]처럼 복사해야 해요. ③ 임시 변수 없는 맞바꾸기 요령: XOR(a ^= b; b ^= a; a ^= b)과 더하고 빼기(a = a + b; b = a - b; a = a - b)는 두 이름이 같은 칸을 가리키면(swap x x) 값이 0이 돼요. 더하고 빼기는 큰 수에서 넘칠 수도 있어요. ④ rot을 임시 변수 없이 x = y; y = z; z = x로 쓰면 z가 이미 바뀐 x(원래 y)를 받아요. 방향도 헷갈리기 쉬워요: x가 y의 값을 받는 쪽이에요. ⑤ 항의 -는 늘 빼기예요. 항 안의 정수에는 부호가 없으니 첫 글자 뒤에서 +나 -를 찾으면 돼요. 크레이콘은 함수 안에서 값을 넣은 이름을 본문 맨 바깥에서도 쓰면(매개변수가 아니면) 그 바깥 변수가 바뀌니, 함수 안의 반복 변수 이름을 바깥과 다르게 지어요.
Pythonmain.py · 42 줄
import syslines = sys.stdin.read().split("\n")q = int(lines[0])reg = {chr(c): 0 for c in range(ord("a"), ord("z") + 1)}def atom(t): return reg[t] if t.isalpha() else int(t)def term(t): # p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없어서 -는 늘 빼기다 for op in "+-": i = t.find(op) if i > 0: a, b = atom(t[:i]), atom(t[i + 1:]) return a + b if op == "+" else a - b return atom(t)out = []for line in lines[1:1 + q]: p = line.split() cmd = p[0] if cmd == "set": reg[p[1]] = int(p[2]) elif cmd == "swap": x, y = p[1], p[2] reg[x], reg[y] = reg[y], reg[x] # x와 y가 같아도 그대로 elif cmd == "rot": x, y, z = p[1], p[2], p[3] reg[x], reg[y], reg[z] = reg[y], reg[z], reg[x] elif cmd == "let": eq = p.index("=") targets = p[1:eq] values = [term(t) for t in p[eq + 1:]] # 오른쪽을 모두 먼저 계산한다 for x, v in zip(targets, values): reg[x] = v else: # show out.append(" ".join(str(reg[x]) for x in p[1:]))print("\n".join(out))
JavaScriptmain.js · 40 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const reg = new Array(26).fill(0);const at = (x) => x.charCodeAt(0) - 97; // 'a' → 0const atom = (t) => (/^[a-z]$/.test(t) ? reg[at(t)] : Number(t));function term(t) { // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다 const i = t.search(/[+-]/); if (i <= 0) return atom(t); const a = atom(t.slice(0, i)); const b = atom(t.slice(i + 1)); return t[i] === "+" ? a + b : a - b;}const out = [];for (const line of lines.slice(1, 1 + q)) { const p = line.trim().split(" "); const cmd = p[0]; if (cmd === "set") { reg[at(p[1])] = Number(p[2]); } else if (cmd === "swap") { const x = at(p[1]); const y = at(p[2]); [reg[x], reg[y]] = [reg[y], reg[x]]; // 구조 분해로 한꺼번에 바꾼다 } else if (cmd === "rot") { const [x, y, z] = p.slice(1).map(at); [reg[x], reg[y], reg[z]] = [reg[y], reg[z], reg[x]]; } else if (cmd === "let") { const eq = p.indexOf("="); const values = p.slice(eq + 1).map(term); // 오른쪽을 모두 먼저 계산한다 p.slice(1, eq).forEach((x, i) => { reg[at(x)] = values[i]; }); } else { out.push(p.slice(1).map((x) => reg[at(x)]).join(" ")); }}console.log(out.join("\n"));
TypeScriptmain.ts · 42 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q = Number(lines[0]);const reg: number[] = new Array<number>(26).fill(0);const at = (x: string): number => x.charCodeAt(0) - 97; // 'a' → 0const atom = (t: string): number => (/^[a-z]$/.test(t) ? reg[at(t)] : Number(t));function term(t: string): number { // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다 const i = t.search(/[+-]/); if (i <= 0) return atom(t); const a = atom(t.slice(0, i)); const b = atom(t.slice(i + 1)); return t[i] === "+" ? a + b : a - b;}const out: string[] = [];for (const line of lines.slice(1, 1 + q)) { const p = line.trim().split(" "); const cmd = p[0]; if (cmd === "set") { reg[at(p[1])] = Number(p[2]); } else if (cmd === "swap") { const x = at(p[1]); const y = at(p[2]); [reg[x], reg[y]] = [reg[y], reg[x]]; // 구조 분해로 한꺼번에 바꾼다 } else if (cmd === "rot") { const [x, y, z] = p.slice(1).map(at); [reg[x], reg[y], reg[z]] = [reg[y], reg[z], reg[x]]; } else if (cmd === "let") { const eq = p.indexOf("="); const values: number[] = p.slice(eq + 1).map(term); // 오른쪽을 모두 먼저 계산한다 p.slice(1, eq).forEach((x, i) => { reg[at(x)] = values[i]; }); } else { out.push(p.slice(1).map((x) => reg[at(x)]).join(" ")); }}console.log(out.join("\n"));
JavaMain.java · 68 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringJoiner;public class Main { static int[] reg = new int[26]; static int at(String x) { return x.charAt(0) - 'a'; } static int atom(String t) { return Character.isLetter(t.charAt(0)) ? reg[at(t)] : Integer.parseInt(t); } static int term(String t) { // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다 for (int i = 1; i < t.length(); i++) { char c = t.charAt(i); if (c == '+' || c == '-') { int a = atom(t.substring(0, i)); int b = atom(t.substring(i + 1)); return c == '+' ? a + b : a - b; } } return atom(t); } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int q = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int t = 0; t < q; t++) { String[] p = in.readLine().trim().split(" "); switch (p[0]) { case "set" -> reg[at(p[1])] = Integer.parseInt(p[2]); case "swap" -> { int x = at(p[1]), y = at(p[2]); int tmp = reg[x]; // Java에는 a, b = b, a가 없어서 임시 변수를 쓴다 reg[x] = reg[y]; reg[y] = tmp; } case "rot" -> { int x = at(p[1]), y = at(p[2]), z = at(p[3]); int tmp = reg[x]; reg[x] = reg[y]; reg[y] = reg[z]; reg[z] = tmp; } case "let" -> { int eq = 1; while (!p[eq].equals("=")) eq++; int k = eq - 1; int[] values = new int[k]; // 오른쪽을 모두 먼저 계산해 둔다 for (int i = 0; i < k; i++) values[i] = term(p[eq + 1 + i]); for (int i = 0; i < k; i++) reg[at(p[1 + i])] = values[i]; } default -> { StringJoiner sj = new StringJoiner(" "); for (int i = 1; i < p.length; i++) sj.add(String.valueOf(reg[at(p[i])])); out.append(sj).append('\n'); } } } System.out.print(out); }}
C#Main.cs · 62 줄
using System;using System.Linq;using System.Text;class Program{ static int[] reg = new int[26]; static int At(string x) => x[0] - 'a'; static int Atom(string t) => char.IsLetter(t[0]) ? reg[At(t)] : int.Parse(t); static int Term(string t) { // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다 int i = t.IndexOfAny(new[] { '+', '-' }, 1); if (i < 0) return Atom(t); int a = Atom(t.Substring(0, i)); int b = Atom(t.Substring(i + 1)); return t[i] == '+' ? a + b : a - b; } static void Main() { int q = int.Parse(Console.ReadLine().Trim()); var sb = new StringBuilder(); for (int t = 0; t < q; t++) { string[] p = Console.ReadLine().Trim().Split(' '); switch (p[0]) { case "set": reg[At(p[1])] = int.Parse(p[2]); break; case "swap": { int x = At(p[1]), y = At(p[2]); (reg[x], reg[y]) = (reg[y], reg[x]); // 튜플로 한꺼번에 바꾼다 break; } case "rot": { int x = At(p[1]), y = At(p[2]), z = At(p[3]); (reg[x], reg[y], reg[z]) = (reg[y], reg[z], reg[x]); break; } case "let": { int eq = Array.IndexOf(p, "="); // 오른쪽을 모두 먼저 계산해 배열로 받아 둔다 int[] values = p.Skip(eq + 1).Select(Term).ToArray(); for (int i = 0; i < values.Length; i++) reg[At(p[1 + i])] = values[i]; break; } default: sb.Append(string.Join(" ", p.Skip(1).Select(x => reg[At(x)]))).Append('\n'); break; } } Console.Write(sb); }}
C++main.cpp · 58 줄
#include <array>#include <iostream>#include <sstream>#include <string>#include <utility>#include <vector>std::array<int, 26> reg{};int atom(const std::string &t) { return std::isalpha(static_cast<unsigned char>(t[0])) ? reg[t[0] - 'a'] : std::stoi(t);}int term(const std::string &t) { // 항 안의 수에는 부호가 없어서 첫 글자 뒤의 + 나 - 는 늘 계산 기호다 std::size_t i = t.find_first_of("+-", 1); if (i == std::string::npos) return atom(t); int a = atom(t.substr(0, i)), b = atom(t.substr(i + 1)); return t[i] == '+' ? a + b : a - b;}int main() { std::string line; std::getline(std::cin, line); int q = std::stoi(line); std::string out; for (int c = 0; c < q; c++) { std::getline(std::cin, line); std::istringstream ss(line); std::vector<std::string> p; for (std::string w; ss >> w;) p.push_back(w); if (p[0] == "set") { reg[p[1][0] - 'a'] = std::stoi(p[2]); } else if (p[0] == "swap") { std::swap(reg[p[1][0] - 'a'], reg[p[2][0] - 'a']); } else if (p[0] == "rot") { int &x = reg[p[1][0] - 'a'], &y = reg[p[2][0] - 'a'], &z = reg[p[3][0] - 'a']; int tmp = x; x = y; y = z; z = tmp; } else if (p[0] == "let") { std::size_t eq = 1; while (p[eq] != "=") eq++; std::vector<int> values; // 오른쪽을 모두 먼저 계산한다 for (std::size_t i = eq + 1; i < p.size(); i++) values.push_back(term(p[i])); for (std::size_t i = 0; i < values.size(); i++) reg[p[1 + i][0] - 'a'] = values[i]; } else { for (std::size_t i = 1; i < p.size(); i++) { if (i > 1) out += ' '; out += std::to_string(reg[p[i][0] - 'a']); } out += '\n'; } } std::cout << out; return 0;}
Cmain.c · 60 줄
#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>static int reg[26];static int atom(const char *t, int len) { if (isalpha((unsigned char)t[0])) return reg[t[0] - 'a']; int v = 0; for (int i = 0; i < len; i++) v = v * 10 + (t[i] - '0'); return v;}/* p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없다 */static int term(const char *t) { int n = (int)strlen(t); for (int i = 1; i < n; i++) if (t[i] == '+' || t[i] == '-') { int a = atom(t, i), b = atom(t + i + 1, n - i - 1); return t[i] == '+' ? a + b : a - b; } return atom(t, n);}int main(void) { static char line[1024]; char *tok[64]; fgets(line, sizeof line, stdin); int q = atoi(line); for (int c = 0; c < q; c++) { fgets(line, sizeof line, stdin); int k = 0; for (char *s = strtok(line, " \r\n"); s; s = strtok(NULL, " \r\n")) tok[k++] = s; if (strcmp(tok[0], "set") == 0) { reg[tok[1][0] - 'a'] = atoi(tok[2]); } else if (strcmp(tok[0], "swap") == 0) { int x = tok[1][0] - 'a', y = tok[2][0] - 'a'; int tmp = reg[x]; /* 임시 칸에 하나를 맡겨 둔다 */ reg[x] = reg[y]; reg[y] = tmp; } else if (strcmp(tok[0], "rot") == 0) { int x = tok[1][0] - 'a', y = tok[2][0] - 'a', z = tok[3][0] - 'a'; int tmp = reg[x]; reg[x] = reg[y]; reg[y] = reg[z]; reg[z] = tmp; } else if (strcmp(tok[0], "let") == 0) { int eq = 1; while (strcmp(tok[eq], "=") != 0) eq++; int n = eq - 1, values[26]; for (int i = 0; i < n; i++) values[i] = term(tok[eq + 1 + i]); /* 먼저 모두 계산 */ for (int i = 0; i < n; i++) reg[tok[1 + i][0] - 'a'] = values[i]; } else { for (int i = 1; i < k; i++) printf(i > 1 ? " %d" : "%d", reg[tok[i][0] - 'a']); putchar('\n'); } } return 0;}
Craykonmain.cray · 77 줄
q = 콘솔.줄읽기().수로변환();reg = 사전();반복 (i = 0; i < 26; i++){ reg[글자.글자로변환(97 + i)] = 0;}하나(t){ 만약 (reg.있나(t)) { 돌려주기 reg[t]; } 돌려주기 t.수로변환();}// p+q, p-q, 또는 칸 이름·수 하나. 항 안의 수에는 부호가 없다항(t){ // 함수 안에서 넣은 이름이 밖에도 있으면 밖의 변수가 바뀌니, 밖에서 안 쓰는 이름(w)을 쓴다 반복 (w = 1; w < t.길이; w++) { 만약 (t[w] == "+" || t[w] == "-") { 가 = 하나(t.부분문자열(0, w)); 나머지 = 하나(t.부분문자열(w + 1)); 만약 (t[w] == "+") { 돌려주기 가 + 나머지; } 돌려주기 가 - 나머지; } } 돌려주기 하나(t);}반복 (c = 0; c < q; c++){ p = 콘솔.줄읽기().공백제거().나누기(" "); 선택 (p[0]) { 경우 "set": reg[p[1]] = p[2].수로변환(); 그만; 경우 "swap": 임시 = reg[p[1]]; // 크레이콘에는 한꺼번에 넣기가 없어서 임시 변수에 맡긴다 reg[p[1]] = reg[p[2]]; reg[p[2]] = 임시; 그만; 경우 "rot": 임시 = reg[p[1]]; reg[p[1]] = reg[p[2]]; reg[p[2]] = reg[p[3]]; reg[p[3]] = 임시; 그만; 경우 "let": eq = p.자리찾기("="); 값들 = []; // 오른쪽을 모두 먼저 계산해 둔다 반복 (i = eq + 1; i < p.개수; i++) { 값들.넣기(항(p[i])); } 반복 (i = 0; i < 값들.개수; i++) { reg[p[1 + i]] = 값들[i]; } 그만; 그밖에: 보일것 = []; 반복 (i = 1; i < p.개수; i++) { 보일것.넣기(reg[p[i]]); } 콘솔.쓰기(보일것.잇기(" ")); 그만; }}