3개에서 5개의 음이 주어질 때, 그 음 집합과 정확히 일치하는 모든 코드 이름(기본 코드와 선택적 텐션)을 ASCII 순서로 출력합니다.
보통4해시맵수학완전 탐색구현아직 제출이 없습니다시간 제한8초메모리 제한512 MB주어진 음 집합을 정확히 나타내는 코드 이름을 모두 출력한다.
음계는 다음 12개의 음으로 이루어진다.
C, C#, D, D#, E, F, F#, G, G#, A, A#, B
이웃한 두 음은 반음 차이이고 오른쪽 음이 더 높다. 그래서 G는 E보다 반음 세 개만큼 높다. C는 B보다 반음 하나 높다. 엄밀히 말하면 B 다음에 오는 C는 다음 옥타브의 음이지만, 이 문제에서 옥타브는 구분하지 않는다. 즉 음은 12로 나눈 나머지로 센 거리다.
코드는 서로 다른 두 개 이상의 음으로 이루어진 집합이고, 코드 이름으로 부른다. 한 코드에 여러 코드 이름이 붙기도 하지만, 코드 이름 하나는 음 집합 하나만 나타낸다.
코드 이름은 기본 코드 뒤에 텐션을 최대 하나 붙인 형태다. 기본 코드는 다섯 가지이고, 근음이 C인 경우는 다음과 같다.
| 코드 이름 | 구성음 |
|---|---|
| C | C, E, G |
| C7 | C, E, G, A# |
| CM7 | C, E, G, B |
| Cm | C, D#, G |
| Cm7 | C, D#, G, A# |
코드를 쌓아 올리는 기준음, 위 다섯 코드에서는 C가 그 코드의 근음이다. 코드 이름은 근음을 절대음으로 지정하고 나머지 구성음은 근음에서 떨어진 반음 수로 지정한다. 그래서 근음을 옮기면 구성음도 모두 함께 옮겨간다. 코드 이름 D는 음 D, F#, A를 나타내고, 이는 C, E, G를 반음 두 개만큼 올린 것이다.
텐션은 부호 없는 숫자이거나 앞에 더하기나 빼기 부호가 붙은 숫자이고, 기본 코드 뒤 괄호 안에 쓴다. 숫자는 근음에서 떨어진 거리를 뜻한다.
| 텐션 | 근음보다 높은 반음 수 | 근음이 C일 때의 음 |
|---|---|---|
| -9 | 1 | C# |
| 9 | 2 | D |
| +9 | 3 | D# |
| -11 | 4 | E |
| 11 | 5 | F |
| +11 | 6 | F# |
| -13 | 8 | G# |
| 13 | 9 | A |
| +13 | 10 | A# |
C(9)는 코드 C에 음 D를 더한 것, 즉 집합 C, D, E, G다. C(+11)은 코드 C에 음 F#을 더한 것이다. 숫자가 근음에서부터 세는 거리이므로 근음이 바뀌면 그 숫자가 가리키는 음도 바뀐다. 아래 두 그림이 이를 보여준다.

그림 1: 근음이 C인 코드의 텐션

그림 2: 근음이 E인 코드의 텐션
텐션 +5와 −5는 특별하다. 음을 더하지 않고, 근음보다 반음 일곱 개 높은 구성음인 5음을 반음 올리거나 내린다. 그래서 C(+5)는 집합 C, E, G, G#이 아니라 집합 C, E, G#이다.
나머지 텐션은 음을 정확히 하나 더하며, 그 음은 기본 코드에 이미 들어 있는 음이 아니다. 텐션이 가리키는 음이 자기 기본 코드의 구성음과 겹치는 이름은 코드 이름이 아니고, 출력하지 않는다. −11은 음 E를 가리키고 코드 C는 이미 E를 가지므로 C(-11)은 코드 이름이 아니다.
코드 이름의 문법을 배커스 나우르 형식으로 쓰면 다음과 같다.
chord ::= base_chord tension_part?
base_chord ::= root_spec ( "" | "7" | "M7" | "m" | "m7" )
root_spec ::= tone
tone ::= "C" | "C#" | "D" | "D#" | "E" | "F" | "F#" | "G" | "G#" | "A" | "A#" | "B"
tension_part ::= "(" tension ")"
tension ::= ( ("+" | "-")? ("9" | "11" | "13") ) | ( ("+" | "-") "5" )
음 C, E, G의 코드 이름을 찾는다고 하자. 기본 코드 표에서 C를 바로 찾을 수 있으니 C가 답 하나다. 답이 하나 더 있다. Em은 집합 E, G, B인데, 5음인 B를 반음 올리면 C가 되어 E, G, C가 남는다. 이 변형은 텐션 +5로 적으므로 Em(+5)가 두 번째 답이다.
첫째 줄에 테스트 케이스의 수 N이 주어진다 (1≤N≤2000).
다음 N개 줄에는 각각 정수 m (3≤m≤5)과 음 m개가 주어지며, 이웃한 두 항목 사이에는 공백이 정확히 하나씩 있다. 모든 음은 위에 적은 12개 이름 중 하나이고, 한 줄에 같은 음이 두 번 나오지 않는다.
테스트 케이스마다 한 줄씩 출력한다.
그 줄에는 음 집합이 입력으로 주어진 집합과 같은 코드 이름을 모두 공백 하나로 구분해 출력하고, 다른 공백은 넣지 않는다. 같은 코드 이름은 한 번만 출력한다.
이름은 문자를 ASCII 코드로 하나씩 비교해 오름차순으로 출력한다. 이 순서에서는 #이 가장 앞이고 그다음이 (, +, -, 숫자, 대문자, 소문자 순이다. 그래서 C, C#, C(13), C7, CM7, Cm이 정렬된 나열이고 Am(+13)이 Am7보다 앞선다.
집합과 일치하는 코드 이름이 없으면 대문자로 UNKNOWN을 출력한다.