📌 이 문제는 해당 책에서 가져왔습니다.
문제 설명
'큰 수의 법칙'은 다양한 수로 이루어진 배열이 있을 떄 주어진 수들을 M번 더하여 가장 큰 수를 만드는 법칙이다.
단, 배열의 특정한 인덱스(번호)에 해당하는 수가 연속해서 K번을 초과할 수 없는 것이 이 법칙의 특징이다.
입력 조건
출력 조건
이 문제는 전형적인 그리디 알고리즘 문제입니다. 문제 해결을 위한 아이디어를 떠올려보면,
가장 큰 수와 두 번째로 큰 수만 활용하면 됩니다.
연속으로 더할 수 있는 횟수는 최대 번이므로 '가장 큰 수를 K번 더하고 두 번쨰로 큰 수를 한 번 더하는 연산'을 반복하면 됩니다!
코드 구현
# N, M, K를 공백으로 구분하여 입력받기
n, m, k = map(int, input().split())
# N개의 수를 공백으로 구분하여 입력받기
data = list(map(int, input().split()))
data.sort() # 입력받은 수들 정렬하기
first = data[n-1] # 가장 큰 수
second = data[n-2] # 두 번째로 큰 수
result = 0
while True:
for i in range(k): # 가장 큰 수를 K번 더하기
if m == 0: # m이 0이라면 반복문 탈출
break
result += first
m -= 1 # 더할 때마다 1씩 빼기
if m ==0: # m이 0이라면 반복문 탈출
break
result += second # 두 번째로 큰 수를 한 번 더하기
m -= 1 # 더할 때마다 1씩 빼기
print(result) # 최종 답안 출력
이렇게 코드를 작성하면 M의 크기가 커질 수록 시간이 초과될 가능성이 큽니다.
다시 이 문제를 생각해 보려고 합니다.
예를 들어, 이 5이고, 입력값이 아래와 같다면
2 | 4 | 5 | 4 | 6 |
---|
이때 가장 큰 수와 두 번째로 큰 수를 선택합니다.
이때 은 8이고 가 3이라면 다음과 같이 더했을 때 합을 최대로 할 수 있습니다.
6 | 6 | 6 | 5 |
---|
6 | 6 | 6 | 5 |
---|
다시 말해 (6+6+6+5) + (6+6+6+5)로 정답은 46입니다.
여기서는 반복되는 수열에 대해 파악하는 것이 가장 중요합니다.
수열 {6,6,6,5}가 반복되었습니다. 그러면 여기서 수열의 길이는 로 4가 됩니다.
따라서 을 로 나눈 몫이 수열이 반복되는 횟수가 됩니다. (8%4=2)
다시 여기에 를 곱해준다면, 가장 큰 수가 등장하는 횟수가 됩니다. (2*3=6)
이때 이 로 나누어 떨어지지 않는 경우도 고려를 해야하는데요.
그럴 때는 을 로 나눈 나머지만큼 가장 큰 수가 추가로 더해지므로 이를 고려해주면 됩니다.
즉, '가장 큰 수가 더해지는 횟수는 다음과 같습니다.
결과적으로 위의 식을 활용하여 가장 큰 수가 더해지는 횟수를 구한 다음, 이를 이용해 두 번쨰로 큰 수가 더해지는 횟수까지 구할 수 있습니다.
답안 예시
# N, M, K를 공백으로 구분하여 입력받기
n, m, k = map(int, input().split())
# N개의 수를 공백으로 구분하여 입력받기
data = list(map(int, input().split()))
data.sort() # 입력받은 수들 정렬하기
first = data[n-1] # 가장 큰 수
second = data[n-2] # 두 번째로 큰 수
# 가장 큰 수가 더해지는 횟수 계산
count = int(m/(k+1)) * k
count += m % (k+1)
result = 0
result += (count) * first # 가장 큰 수 더하기
result += (m - count) * second # 두 번째로 큰 수 더하기
print(result)
그래서 다시 작성하면 다음과 같습니다.