{ }codelper
switch 语句取余P0401

把乐谱移动 k 个半音

要把乐谱上的每个音都移动 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
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 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":,Craykon 写成 选择 (letter) { 情况 "C": … 跳出; }。
**陷阱一:漏写 break。
** C、C++、Java(冒号形式)、JS、TS 的 switch 没有 break 就会落入下一个 case。
去掉 case 'E': s = 4; 后面的 break,E 就得到 F 的值 5,样例 1 的 E2 会输出 G#2 而不是 G2。
这里的 C 解答在每个分支都写 break,C++、JS、TS 的解答在每个分支用 return 直接返回。
C# 中有内容的 case 落入下一个会编译错误(CS0163),而 Java 的箭头形式、C# 的 switch 表达式、Python 的 match、Craykon 的 选择 都不会落入下一个分支。
**陷阱二:把八度单独放着,只计算音名的位置。
** 用字母的半音数加上升降号和 k 得到 s,再求 NAMES[s % 12] 和 八度 + s / 12,那么样例 2 的 Cb4 中 s 是 -1。
在 C、C++、Java、C#、JS、TS、Craykon 中 -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),Craykon 是 数学.商(p, 12)。
**陷阱三:忘记升降号会跨到另一个八度。
** 选音名时算上了升降号,八度却只由字母和 k 决定,样例 2 的 B#4 就会输出 C4 而不是 C5,Cb4 会输出 B4 而不是 B3。

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  # B  n, 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.连接(" "));