[Bronze I] 전주 듣고 노래 맞히기 - 31562

문제 링크

성능 요약

메모리: 111916 KB, 시간: 224 ms

분류

구현, 자료 구조, 문자열, 브루트포스 알고리즘, 집합과 맵, 해시를 사용한 집합과 맵

제출 일자

2026년 04월 25일 22:04:59

문제 설명

윤수와 정환은 「전주 듣고 노래 맞히기」라는 게임을 할 예정이다. 「전주 듣고 노래 맞히기」는 주어진 노래의 전주를 듣고 먼저 제목을 맞히는 사람이 점수를 얻어 최종적으로 점수가 더 많은 사람이 이기는 게임이다. 절대 음감을 가진 윤수는 노래의 첫 네 음만 듣고도 어떤 노래든 바로 맞힐 수 있다. 따라서, 정환은 윤수를 이기기 위해 첫 세 음만으로 노래를 맞히게 해주는 프로그램을 만들려고 한다. 우선 정환이 알고 있는 노래 제목, 음이름 등을 데이터로 만든 뒤 프로그램을 구현하기 시작했다. 예를 들어, 다음은 TwinkleStar(반짝반짝 작은 별)의 악보 중 일부이다.

위 악보를 박자와 관계없이 음이름으로 표현하면 CCGGAAG가 된다.

윤수를 이기기 위해서는 이 프로그램이 첫 세 음인 CCG만으로 노래 제목인 TwinkleStar를 출력할 수 있어야 한다. 또한, 세상의 모든 노래를 아는 윤수와 다르게 정환은 음을 아는 노래가 $N$개뿐이다. 그래서 프로그램에 $N$개의 노래의 정보를 저장해 놓을 것이다. 만약 저장된 노래 중 입력한 첫 세 음으로 시작하는 노래가 여러 개 있어 무슨 노래인지 정확히 알 수 없는 경우 ?를 출력하고, 입력한 첫 세 음에 맞는 저장된 노래가 없을 경우 !를 출력한다.

정환을 도와서 첫 세 음만으로 본인이 음을 아는 노래를 맞히는 프로그램을 완성하자. 이 프로그램은 대문자와 소문자를 구분한다.

입력

첫 번째 줄에 정환이 음을 아는 노래의 개수 $N$, 정환이 맞히기를 시도할 노래의 개수 $M$이 공백으로 구분되어 주어진다.

두 번째 줄부터 $N$개의 줄에 걸쳐 노래 제목의 길이 $T$, 영어 대소문자로 이루어진 문자열 노래 제목 $S$, 해당 노래에서 처음 등장하는 일곱 개의 음이름 $a_1, a_2, a_3, a_4, a_5, a_6, a_7$이 공백으로 구분되어 주어진다.

$N+2$번째 줄부터 $M$개의 줄에 걸쳐 정환이 맞히기를 시도할 노래의 첫 세 음의 음이름 $b_1, b_2, b_3$가 공백으로 구분되어 주어진다.

주어지는 음이름은 각각 C, D, E, F, G, A, B 중 하나이다. 같은 제목이 두 번 이상 주어지지 않는다.

출력

정환이 맞히기를 시도할 각 노래에 대하여 프로그램에 저장된 노래와 첫 세 음이 동일한 노래가 하나만 있다면 해당 노래의 제목을, 두 개 이상이면 ?을, 없다면 !을 한 줄에 하나씩 출력한다.


💡 해결 방법

💻 코드

 
# 윤수와 정환은 「전주 듣고 노래 맞히기」라는 게임을 할 예정이다. 「전주 듣고 노래 맞히기」는 주어진 노래의 전주를 듣고 먼저 제목을 맞히는 사람이 점수를 얻어 최종적으로 점수가 더 많은 사람이 이기는 게임이다. 절대 음감을 가진 윤수는 노래의 첫 네 음만 듣고도 어떤 노래든 바로 맞힐 수 있다. 따라서, 정환은 윤수를 이기기 위해 첫 세 음만으로 노래를 맞히게 해주는 프로그램을 만들려고 한다. 우선 정환이 알고 있는 노래 제목, 음이름 등을 데이터로 만든 뒤 프로그램을 구현하기 시작했다. 예를 들어, 다음은 TwinkleStar(반짝반짝 작은 별)의 악보 중 일부이다.
 
 
 
# 위 악보를 박자와 관계없이 음이름으로 표현하면 CCGGAAG가 된다.
 
# 윤수를 이기기 위해서는 이 프로그램이 첫 세 음인 CCG만으로 노래 제목인 TwinkleStar를 출력할 수 있어야 한다. 또한, 세상의 모든 노래를 아는 윤수와 다르게 정환은 음을 아는 노래가 $N$개뿐이다. 그래서 프로그램에 $N$개의 노래의 정보를 저장해 놓을 것이다. 만약 저장된 노래 중 입력한 첫 세 음으로 시작하는 노래가 여러 개 있어 무슨 노래인지 정확히 알 수 없는 경우 ?를 출력하고, 입력한 첫 세 음에 맞는 저장된 노래가 없을 경우 !를 출력한다.
 
# 정환을 도와서 첫 세 음만으로 본인이 음을 아는 노래를 맞히는 프로그램을 완성하자. 이 프로그램은 대문자와 소문자를 구분한다.
 
# 입력
# 첫 번째 줄에 정환이 음을 아는 노래의 개수 $N$, 정환이 맞히기를 시도할 노래의 개수 $M$이 공백으로 구분되어 주어진다.
 
# 두 번째 줄부터 $N$개의 줄에 걸쳐 노래 제목의 길이 $T$, 영어 대소문자로 이루어진 문자열 노래 제목 $S$, 해당 노래에서 처음 등장하는 일곱 개의 음이름 $a_1, a_2, a_3, a_4, a_5, a_6, a_7$이 공백으로 구분되어 주어진다.
 
#  $N+2$번째 줄부터 $M$개의 줄에 걸쳐 정환이 맞히기를 시도할 노래의 첫 세 음의 음이름 $b_1, b_2, b_3$가 공백으로 구분되어 주어진다.
 
# 주어지는 음이름은 각각 C, D, E, F, G, A, B 중 하나이다. 같은 제목이 두 번 이상 주어지지 않는다.
 
# 출력
# 정환이 맞히기를 시도할 각 노래에 대하여 프로그램에 저장된 노래와 첫 세 음이 동일한 노래가 하나만 있다면 해당 노래의 제목을, 두 개 이상이면 ?을, 없다면 !을 한 줄에 하나씩 출력한다.
 
# 제한
#  $1 \le N \le 1\,000$ 
#  $1 \le M \le 1\,000$ 
#  $1 \le T \le 30$ 
# 입력으로 주어지는 모든 수는 정수이다.
# 예제 입력 1 
# 4 4
# 11 TwinkleStar C C G G A A G
# 8 Marigold E D E F E E D
# 23 DoYouWannaBuildASnowMan C C C G C E D
# 12 Cprogramming C C C C C C C
# E D E
# C G G
# C C C
# C C G
# 예제 출력 1 
# Marigold
# !
# ?
# TwinkleStar
 
 
n1, n2 = map(int, input().split())
 
list1 = []
for _ in range(0, n1):
    templist = input().split()
    b = templist[1]
    c = templist[2:]
    list1.append([c, b])
 
# print(*list1, sep = '\n')
 
list2 = [i[0][:3] for i in list1], [i[1] for i in list1]
 
# print()
# print(*list2, sep = '\n')
  
for _ in range(0, n2):
    tempin = input().split()
    if list2[0].count(tempin) >= 2:
        print('?')
    elif list2[0].count(tempin) == 1:
        idx = list2[0].index(tempin)
        print(list2[1][idx])
    else:
        print('!')