악보에 적힌 음을 모두 k반음씩 옮겨 적으려 한다. 음은 음이름 뒤에 옥타브 숫자를 붙여 C4, F#3, Bb5처럼 적는다. 음이름은 대문자 C, D, E, F, G, A, B 가운데 한 글자이고, 그 바로 뒤에 올림표 #이나 내림표 b(소문자)가 하나 붙을 수 있다. 올림표와 내림표는 일곱 글자 어디에나 붙을 수 있어서 E#, Fb, B#, Cb도 입력에 나온다. 글자마다 정해진 반음 수는 C 0, D 2, E 4, F 5, G 7, A 9, B 11이다. 음의 높이는 (옥타브 숫자) × 12 + (글자의 반음 수)이고, 올림표가 붙으면 여기에 1을 더하고 내림표가 붙으면 1을 뺀다. 그래서 B#4와 C5는 높이가 60으로 같고, Cb4와 B3은 높이가 47로 같다. 음마다 높이에 k를 더한 새 높이를 구해, 그 높이의 음을 다음 규칙으로 적어 출력하라. 새 높이를 12로 나눈 나머지 0, 1, 2, …, 11에 차례로 음이름 C, C#, D, D#, E, F, F#, G, G#, A, A#, B를 쓴다. 그 뒤에 새 높이를 12로 나눈 몫을 옥타브 숫자로 붙인다. 출력에는 내림표를 쓰지 않는다.
입력
첫 줄에 음의 개수 n과 옮길 반음 수 k가 빈칸 하나로 띄워 주어진다. 둘째 줄에 음 n개가 빈칸 하나로 띄워 주어진다. 1 ≤ n ≤ 1000, -12 ≤ k ≤ 12이고, k가 음수이면 높이가 낮아진다. 입력에 적힌 옥타브 숫자는 2 이상 6 이하이다. 따라서 새 높이는 늘 11 이상 96 이하이다.
출력
옮긴 음 n개를 입력된 순서대로 한 줄에 빈칸 하나로 띄워 출력한다.
예시 1 · stdin
5 3
C4 B4 F#3 Bb5 E2
stdout
D#4 D5 A3 C#6 G2
예시 2 · stdin
3 0
B#4 Cb4 Fb3
stdout
C5 B3 E3
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
글자 하나를 수로 바꾸는 일곱 갈래가 이 문제의 switch예요. C·C++의 switch는 정수와 문자만 받아서 case 'C':처럼 쓰고, 문자열을 넣으면 컴파일 오류예요. JS·TS는 case "C":로 문자열도 견줄 수 있어요. Java는 화살표 꼴 case 'C' -> 0;, C#은 switch 식 'C' => 0,, Python은 3.10부터 있는 match/case "C":, 크레이콘은 선택 (letter) { 경우 "C": … 그만; }으로 써요. 함정 하나: break를 빠뜨리기. C·C++·Java(콜론 꼴)·JS·TS의 switch는 break가 없으면 다음 case로 이어 내려가요. case 'E': s = 4; 뒤의 break를 빼면 E가 F의 값 5를 받아서, 예시 1의 E2가 G2가 아니라 G#2로 나와요. 여기 실린 C 풀이는 갈래마다 break를 쓰고, C++·JS·TS 풀이는 갈래마다 return으로 바로 나가요. C#은 내용이 있는 case가 다음으로 이어 내려가면 컴파일 오류(CS0163)이고, Java의 화살표 꼴, C#의 switch 식, Python의 match, 크레이콘의 선택은 이어 내려가지 않아요. 함정 둘: 옥타브를 따로 두고 음이름 자리만 계산하기. 글자의 반음 수에 올림표·내림표와 k를 더한 값 s로 NAMES[s % 12]와 옥타브 + s / 12를 구하면, 예시 2의 Cb4에서 s가 -1이 돼요. C·C++·Java·C#·JS·TS·크레이콘에서 -1 % 12는 -1이라 목록 밖을 가리켜요. JS에서는 NAMES[-1]이 undefined이고 여기에 수를 더해 NaN이 찍혀요. Python만은 -1 % 12가 11, -1 // 12가 -1이라 같은 식으로도 B3이 나와요. 여기 실린 풀이는 모두 옥타브 × 12까지 합친 높이 하나로 계산해요. 높이는 늘 11 이상이라 어느 언어에서도 나머지와 몫이 음수가 되지 않아요. 몫은 C·C++·Java·C#에서는 정수끼리의 /, Python은 //, JS·TS는 Math.floor(p / 12), 크레이콘은 수학.몫(p, 12)예요. 함정 셋: 올림표·내림표가 옥타브를 넘기는 것을 잊기. 음이름은 올림표까지 넣어 고르면서 옥타브는 글자와 k만으로 정하면, 예시 2의 B#4가 C5가 아니라 C4로, Cb4가 B3이 아니라 B4로 나와요.
Pythonmain.py · 31 줄
NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]def semitone(letter): # 음이름 글자가 C에서 반음 몇 개 위인지 (match는 다음 case로 이어 내려가지 않는다) match letter: case "C": return 0 case "D": return 2 case "E": return 4 case "F": return 5 case "G": return 7 case "A": return 9 case _: return 11 # Bn, k = map(int, input().split())out = []for note in input().split(): p = int(note[-1]) * 12 + semitone(note[0]) # 음 번호: 옥타브와 음이름을 한 수로 if len(note) == 3: p += 1 if note[1] == "#" else -1 p += k out.append(NAMES[p % 12] + str(p // 12))print(" ".join(out))
JavaScriptmain.js · 25 줄
const NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지function semitone(letter) { switch (letter) { case "C": return 0; case "D": return 2; case "E": return 4; case "F": return 5; case "G": return 7; case "A": return 9; default: return 11; // B }}const lines = require("fs").readFileSync(0, "utf8").split("\n");const k = Number(lines[0].trim().split(/\s+/)[1]);const out = lines[1].trim().split(/\s+/).map((note) => { // 음 번호: 옥타브와 음이름을 한 수로 합친다 let p = Number(note[note.length - 1]) * 12 + semitone(note[0]); if (note.length === 3) p += note[1] === "#" ? 1 : -1; p += k; return NAMES[p % 12] + Math.floor(p / 12);});console.log(out.join(" "));
TypeScriptmain.ts · 27 줄
import { readFileSync } from "node:fs";const NAMES: string[] = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지function semitone(letter: string): number { switch (letter) { case "C": return 0; case "D": return 2; case "E": return 4; case "F": return 5; case "G": return 7; case "A": return 9; default: return 11; // B }}const lines: string[] = readFileSync(0, "utf8").split("\n");const k: number = Number(lines[0].trim().split(/\s+/)[1]);const out: string[] = lines[1].trim().split(/\s+/).map((note: string): string => { // 음 번호: 옥타브와 음이름을 한 수로 합친다 let p: number = Number(note[note.length - 1]) * 12 + semitone(note[0]); if (note.length === 3) p += note[1] === "#" ? 1 : -1; p += k; return NAMES[p % 12] + Math.floor(p / 12);});console.log(out.join(" "));
JavaMain.java · 35 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { static final String[] NAMES = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; // 음이름 글자가 C에서 반음 몇 개 위인지 (화살표 switch는 이어 내려가지 않는다) static int semitone(char letter) { return switch (letter) { case 'C' -> 0; case 'D' -> 2; case 'E' -> 4; case 'F' -> 5; case 'G' -> 7; case 'A' -> 9; default -> 11; // B }; } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int k = Integer.parseInt(in.readLine().trim().split("\\s+")[1]); StringBuilder out = new StringBuilder(); for (String note : in.readLine().trim().split("\\s+")) { // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note.charAt(note.length() - 1) - '0') * 12 + semitone(note.charAt(0)); if (note.length() == 3) p += note.charAt(1) == '#' ? 1 : -1; p += k; if (out.length() > 0) out.append(' '); out.append(NAMES[p % 12]).append(p / 12); } System.out.println(out); }}
C#Main.cs · 34 줄
using System;using System.Collections.Generic;class Program{ static readonly string[] Names = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; // 음이름 글자가 C에서 반음 몇 개 위인지 static int Semitone(char letter) => letter switch { 'C' => 0, 'D' => 2, 'E' => 4, 'F' => 5, 'G' => 7, 'A' => 9, _ => 11, // B }; static void Main() { int k = int.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]); var result = new List<string>(); foreach (string note in Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)) { // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note[note.Length - 1] - '0') * 12 + Semitone(note[0]); if (note.Length == 3) p += note[1] == '#' ? 1 : -1; p += k; result.Add(Names[p % 12] + (p / 12)); } Console.WriteLine(string.Join(" ", result)); }}
C++main.cpp · 35 줄
#include <iostream>#include <string>using namespace std;const string NAMES[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};// 음이름 글자가 C에서 반음 몇 개 위인지int semitone(char letter) { switch (letter) { case 'C': return 0; case 'D': return 2; case 'E': return 4; case 'F': return 5; case 'G': return 7; case 'A': return 9; default: return 11; // B }}int main() { int n, k; cin >> n >> k; for (int i = 0; i < n; i++) { string note; cin >> note; // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note.back() - '0') * 12 + semitone(note[0]); if (note.size() == 3) p += note[1] == '#' ? 1 : -1; p += k; if (i) cout << ' '; cout << NAMES[p % 12] << p / 12; } cout << '\n'; return 0;}
Cmain.c · 36 줄
#include <stdio.h>#include <string.h>static const char *NAMES[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};/* 음이름 글자가 C에서 반음 몇 개 위인지 */static int semitone(char letter) { int s; switch (letter) { case 'C': s = 0; break; case 'D': s = 2; break; case 'E': s = 4; break; case 'F': s = 5; break; case 'G': s = 7; break; case 'A': s = 9; break; default: s = 11; break; /* B */ } return s;}int main(void) { int n, k; char note[8]; scanf("%d %d", &n, &k); for (int i = 0; i < n; i++) { scanf("%7s", note); size_t len = strlen(note); /* 음 번호: 옥타브와 음이름을 한 수로 합친다 */ int p = (note[len - 1] - '0') * 12 + semitone(note[0]); if (len == 3) p += note[1] == '#' ? 1 : -1; p += k; printf("%s%s%d", i ? " " : "", NAMES[p % 12], p / 12); } printf("\n"); return 0;}
Craykonmain.cray · 53 줄
names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지반음(letter){ s = 11; // B 선택 (letter) { 경우 "C": s = 0; 그만; 경우 "D": s = 2; 그만; 경우 "E": s = 4; 그만; 경우 "F": s = 5; 그만; 경우 "G": s = 7; 그만; 경우 "A": s = 9; 그만; } 돌려주기 s;}first = 콘솔.수들읽기();k = first[1];notes = 콘솔.줄읽기().공백제거().나누기(" ");out = [];각각 (note 에서 notes){ // 음 번호: 옥타브와 음이름을 한 수로 합친다 p = note[note.길이 - 1].수로변환() * 12 + 반음(note[0]); 만약 (note.길이 == 3) { 만약 (note[1] == "#") { p = p + 1; } 아니면 { p = p - 1; } } p = p + k; out.넣기(names[p % 12] + 수학.몫(p, 12));}콘솔.쓰기(out.잇기(" "));