CF 102800A - Chord
Each test case describes three musical notes that are already ordered from the lowest pitch to the highest pitch.
Rating: -
Tags: -
Solve time: 1m
Verified: yes
Solution
Problem Understanding
Each test case describes three musical notes that are already ordered from the lowest pitch to the highest pitch. The notes may belong to different octaves, but the input guarantees that the distance from the first note to the second and from the second note to the third is at most 11 semitones. Our task is to determine whether these three notes form a major triad, a minor triad, or neither.
The only information that matters is the number of semitones between consecutive notes. A major triad has intervals of 4 semitones followed by 3 semitones. A minor triad has intervals of 3 semitones followed by 4 semitones. Any other pair of intervals must be reported as Dissonance.
The number of test cases is at most 2000, which is very small. Every test case contains only three notes, so even constant time processing per case is more than sufficient. The solution only needs a mapping from note names to their positions within an octave and a few arithmetic operations.
The first subtle case is when the notes cross an octave boundary. For example,
A C E
The correct output is
Minor triad
The note C has a smaller index than A inside a single octave, but it is actually in the next octave. Simply subtracting octave indices would produce a negative value. The interval computation must add 12 whenever the next note's index is smaller.
Another easy mistake is assuming that every increasing sequence of notes can be classified as a chord. For example,
C F A
The intervals are 5 and 4 semitones, which matches neither chord definition. The correct output is
Dissonance
A final edge case is when the input is musically descending in terms of note names but still ascending in pitch because of octaves.
E D C
The correct output is
Dissonance
Although D and C appear earlier in the chromatic scale, they belong to higher octaves. A solution that ignores octave wrapping would compute incorrect negative distances.
Approaches
A straightforward approach is to simulate the musical definition directly. Convert every note into its position inside an octave, compute the semitone distance between consecutive notes, adjust for octave wrapping whenever necessary, then compare the two distances against the two valid patterns.
One could also imagine generating every possible major and minor triad and checking whether the input matches one of them. Since there are only 12 possible roots and two chord types, this still requires only 24 patterns and is easily fast enough. Although correct, it introduces unnecessary preprocessing and comparisons.
The direct interval computation is simpler because the problem definition is already expressed in terms of consecutive semitone distances. Once each note is mapped to an integer from 0 to 11, every test case reduces to two interval calculations and two comparisons.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(24) per test case | O(24) | Accepted, but unnecessary |
| Optimal | O(1) per test case | O(1) | Accepted |
Algorithm Walkthrough
- Create a mapping from each note name to its position in the chromatic scale.
- Read the three notes and convert them into their numeric positions.
- Compute the interval from the first note to the second. If the second position is smaller, add 12 before subtracting so the interval represents moving upward into the next octave.
- Compute the second interval in exactly the same way.
- If the two intervals are
(4, 3), printMajor triad. - Otherwise, if the intervals are
(3, 4), printMinor triad. - Otherwise, print
Dissonance.
Why it works
The input guarantees that the notes are already ordered from lower pitch to higher pitch. The only complication is that moving upward may cross an octave boundary. Adding 12 whenever the numeric note value decreases reconstructs the actual upward semitone distance. After those two distances are computed, the chord type is determined entirely by the problem definition. Since every possible input produces exactly one pair of consecutive intervals, the algorithm always classifies the chord correctly.
Python Solution
import sys
input = sys.stdin.readline
pos = {
"C": 0,
"C#": 1,
"D": 2,
"D#": 3,
"E": 4,
"F": 5,
"F#": 6,
"G": 7,
"G#": 8,
"A": 9,
"A#": 10,
"B": 11,
}
def interval(a, b):
if b < a:
b += 12
return b - a
t = int(input())
for _ in range(t):
n1, n2, n3 = input().split()
x = pos[n1]
y = pos[n2]
z = pos[n3]
d1 = interval(x, y)
d2 = interval(y, z)
if d1 == 4 and d2 == 3:
print("Major triad")
elif d1 == 3 and d2 == 4:
print("Minor triad")
else:
print("Dissonance")
The dictionary stores the chromatic scale as integers from 0 through 11. This makes interval calculations simple integer subtraction instead of string processing.
The helper function handles the only tricky part of the implementation. When the second note has a smaller numeric value, it belongs to the next octave, so adding 12 reconstructs the correct upward distance. Because the statement guarantees each interval is at most 11 semitones, this adjustment is always sufficient.
Each test case computes two intervals and compares them against the only two valid patterns. There are no off by one issues because the chromatic scale is represented with consecutive integers and every interval is measured directly as the difference between positions after octave adjustment.
Worked Examples
Example 1
Input:
C E G
| Note | Numeric Value |
|---|---|
| C | 0 |
| E | 4 |
| G | 7 |
| d1 | d2 | Result |
|---|---|---|
| 4 | 3 | Major triad |
The intervals match the major triad definition exactly, so the algorithm prints Major triad.
Example 2
Input:
A C E
| Note | Numeric Value |
|---|---|
| A | 9 |
| C | 0 |
| E | 4 |
| d1 | d2 | Result |
|---|---|---|
| (12 + 0) - 9 = 3 | 4 | Minor triad |
This example demonstrates why octave adjustment is necessary. Without adding 12, the first interval would incorrectly become -9.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(T) | Each test case performs constant work. |
| Space | O(1) | Only the fixed note mapping and a few variables are stored. |
Even with the maximum of 2000 test cases, the total work is tiny. The solution easily satisfies the given limits.
Test Cases
import sys
import io
def solve():
import sys
input = sys.stdin.readline
pos = {
"C": 0,
"C#": 1,
"D": 2,
"D#": 3,
"E": 4,
"F": 5,
"F#": 6,
"G": 7,
"G#": 8,
"A": 9,
"A#": 10,
"B": 11,
}
def interval(a, b):
if b < a:
b += 12
return b - a
t = int(input())
out = []
for _ in range(t):
a, b, c = input().split()
d1 = interval(pos[a], pos[b])
d2 = interval(pos[b], pos[c])
if d1 == 4 and d2 == 3:
out.append("Major triad")
elif d1 == 3 and d2 == 4:
out.append("Minor triad")
else:
out.append("Dissonance")
print("\n".join(out))
def run(inp: str) -> str:
backup_stdin = sys.stdin
backup_stdout = sys.stdout
sys.stdin = io.StringIO(inp)
sys.stdout = io.StringIO()
solve()
ans = sys.stdout.getvalue()
sys.stdin = backup_stdin
sys.stdout = backup_stdout
return ans
assert run(
"""5
C E G
A C E
B D F#
C F A
E D C
"""
) == (
"""Major triad
Minor triad
Minor triad
Dissonance
Dissonance
"""
)
assert run(
"""1
C E G
"""
) == (
"""Major triad
"""
)
assert run(
"""1
A C E
"""
) == (
"""Minor triad
"""
)
assert run(
"""1
C F A
"""
) == (
"""Dissonance
"""
)
assert run(
"""1
B D# F#
"""
) == (
"""Major triad
"""
)
| Test input | Expected output | What it validates |
|---|---|---|
C E G |
Major triad |
Standard major chord. |
A C E |
Minor triad |
Correct handling of octave wrapping. |
C F A |
Dissonance |
Invalid interval pattern. |
B D# F# |
Major triad |
Major chord crossing an octave boundary. |
Edge Cases
Consider the input
1
A C E
The mapped values are 9, 0, and 4. The algorithm detects that 0 < 9, adds 12, and computes the first interval as 3. The second interval is 4. Since the interval pair is (3, 4), the output is
Minor triad
This correctly handles octave wrapping.
Now consider
1
C F A
The mapped values are 0, 5, and 9. The intervals become (5, 4). Neither valid chord pattern matches, so the algorithm prints
Dissonance
This confirms that only the two exact interval sequences are accepted.
Finally, consider
1
E D C
The mapped values are 4, 2, and 0. The algorithm computes the intervals as (10, 10) after octave adjustment. Neither pair matches (4, 3) or (3, 4), so the output is
Dissonance
This demonstrates that descending note names do not confuse the interval calculation because octave wrapping is handled explicitly.