[Python] 큰 수의 법칙

미남로그·2021년 12월 2일
0
post-thumbnail

📌 이 문제는 해당 책에서 가져왔습니다.



문제 설명

'큰 수의 법칙'은 다양한 수로 이루어진 배열이 있을 떄 주어진 수들을 M번 더하여 가장 큰 수를 만드는 법칙이다.

단, 배열의 특정한 인덱스(번호)에 해당하는 수가 연속해서 K번을 초과할 수 없는 것이 이 법칙의 특징이다.


입력 조건

  • 첫째 줄에 N(2≤N≤10,000), M(1≤M≤10,000), K(1≤K≤10,000)의 자연수가 주어지며, 각 자연수는 공백으로 구분한다.
  • 둘째 줄에 N개의 자연수가 주어진다. 각 자연수는 공백으로 구분한다. 단, 각각의 자연수는 1 이상 10,000 이하의 수로 주어진다.
  • 입력으로 주어지는 K는 항상 M보다 작거나 같다.

출력 조건

  • 첫째 줄에 동빈이의 큰 수의 법칙에 따라 더해진 답을 출력한다.

이 문제는 전형적인 그리디 알고리즘 문제입니다. 문제 해결을 위한 아이디어를 떠올려보면,

가장 큰 수와 두 번째로 큰 수만 활용하면 됩니다.

연속으로 더할 수 있는 횟수는 최대 KK번이므로 '가장 큰 수를 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의 크기가 커질 수록 시간이 초과될 가능성이 큽니다.

다시 이 문제를 생각해 보려고 합니다.

예를 들어, NN이 5이고, 입력값이 아래와 같다면

24546

이때 가장 큰 수와 두 번째로 큰 수를 선택합니다.

  • 가장 큰 수: 6
  • 두 번째로 큰 수: 5

이때 MM은 8이고 KK가 3이라면 다음과 같이 더했을 때 합을 최대로 할 수 있습니다.

6665
6665

다시 말해 (6+6+6+5) + (6+6+6+5)로 정답은 46입니다.

여기서는 반복되는 수열에 대해 파악하는 것이 가장 중요합니다.

수열 {6,6,6,5}가 반복되었습니다. 그러면 여기서 수열의 길이는 K+1K+1로 4가 됩니다.

따라서 MM(K+1)(K+1)로 나눈 몫이 수열이 반복되는 횟수가 됩니다. (8%4=2)

다시 여기에 KK를 곱해준다면, 가장 큰 수가 등장하는 횟수가 됩니다. (2*3=6)

이때 MM(K+1)(K+1)로 나누어 떨어지지 않는 경우도 고려를 해야하는데요.

그럴 때는 MM(K+1)(K+1)로 나눈 나머지만큼 가장 큰 수가 추가로 더해지므로 이를 고려해주면 됩니다.

즉, '가장 큰 수가 더해지는 횟수는 다음과 같습니다.

int(M/(K+1))K+M%(K+1)int(M/(K+1)) * K + M \% (K+1)

결과적으로 위의 식을 활용하여 가장 큰 수가 더해지는 횟수를 구한 다음, 이를 이용해 두 번쨰로 큰 수가 더해지는 횟수까지 구할 수 있습니다.

답안 예시

# 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)

그래서 다시 작성하면 다음과 같습니다.

profile
미남이 귀엽죠

0개의 댓글