새소식

PS/백준

[백준/31034] 초전도체 부수기 (Python)

  • -

Problem : https://www.acmicpc.net/problem/31034

 

31034번: 초전도체 부수기

당신은 상온 상압 초전도체를 개발하고 세상을 뒤바꿀 논문을 작성했다. 당신은 $N\mathrm{g}$의 초전도체 덩어리를 가지고 있는데, 논문 검증을 위해 $K$개의 연구소에서 초전도체 샘플을 요청했다

www.acmicpc.net

 

Difficulty : Platinum 3

 

Status : Solved

 

Time : 00:18:10

 


 

문제 설명

 

더보기

당신은 상온 상압 초전도체를 개발하고 세상을 뒤바꿀 논문을 작성했다. 당신은 Ng의 초전도체 덩어리를 가지고 있는데, 논문 검증을 위해 K개의 연구소에서 초전도체 샘플을 요청했다! 각 연구소에는 1g 이상의 초전도체 샘플을 보내주면 된다. 다행히도, 당신은 초전도체를 정밀하게 부수는 기술을 가지고 있다. 2 이상의 정수 a에 대하여, aㅎ의 초전도체를 다음과 같은 방법으로 절단할 수 있다

 

  • 1이상 a 미만의 정수 b를 선택한다.
  •  bg 짜리 초전도체와 (a-b)g짜리 초전도체 두 개로 쪼갠다.
  • 이때, a원의 비용이 든다.

 

연구 비용 절감을 위해 초전도체를 K개의 조각으로 자르기 위한 최소 비용은 얼마일지 구해야 한다. 단, 제한 조건하에서 위의 방법을 통해 초전도체를  K개의 조각으로 쪼갤 수 있음을 증명할 수 있다.

 

 

입력 및 출력

 

더보기

입력

첫 번째 줄에 테스트 케이스의 개수 T가 주어진다.
T개의 줄에 이어, 각 테스트 케이스마다 한 줄에 초전도체 덩어리의 무게 N과 초전도체 샘플을 요청한 연구소의 수 K가 공백을 사이에 두고 주어진다.

 

출력

 

각 테스트 케이스마다 초전도체를 K개의 조각으로 자르기 위한 최소 비용을 출력한다.

 

입력 예시

 

3
2 2
5 3
10000 1000

 

출력 예시

 

2
7
19965

 

 


 

풀이

 

덧셈으로 관점을 바꾸어 보자. 초기에는 K개의 조각이 존재하고, K개의 조각을 하나로 합칠 것이다. 이 때 임의의 i와 jg의 조각을 합치면 그 비용은 (i+j)g이 된다. 우리는 다음과 같은 사실을 알 수 있다.

 

  • 조각을 합칠 때, 덧셈은 K-1번 발생한다.
  • 각 덧셈에서 가장 낮은 비용인 두 조각을 합치는 것이 최소 비용이다.
  • 초기 비용이 제일 낮으려면, 가능한 한 최소 단위(1g)인 조각의 개수가 많아야 한다.

 

즉 다음 사실들을 통해 그리디하게 접근해보자.

우리는 초기에 K-1개의 1g의 조각과, 1개의 N-K-1g의 조각을 가지고 있다. 우리는 재귀적으로 다음과 같은 방식으로 빠르게 총 비용을

 

  • 가장 적은 조각(i) 의 개수(j)가 2개 이상일 경우 : 이 조각들만을 짝지어 새로운 조각을 만들자. 새로운 조각은 무게가 i*2이며, 개수는 j // 2가 된다.
  • 가장 적은 조각(i)의 개수가 1개일 경우 : 두 번째로 적은 조각 하나(k)를 사용하여 둘을 합치자. 새 조각은 무게가 i + k이며, 개수는 1개이다.

 

이 과정을 1개의 조각이 남을 때까지 반복하면 된다. 트리 기반의 SortedList 등을 사용하면 좀 더 구현이 쉽겠지만, 아쉽게도 파이썬 내장 모듈은 이를 지원하지 않아 힙과 카운팅 딕셔너리를 이용해 유사하게 구현하였다.

 

 

 

풀이 코드

from collections import defaultdict
from heapq import *
import sys
input = sys.stdin.readline

def solve():
  N, K = map(int, input().split())
  count = defaultdict(int)
  count[1] += K - 1
  count[N - K + 1] += 1
  q = list(count.keys())
  heapify(q)
  ans = 0
  
  while sum(count.values()) > 1:
    if count[q[0]] > 1:
      key, val = q[0] * 2, count[q[0]] // 2
      if key not in count:
        heappush(q, key)
      count[key] += val
      count[q[0]] %= 2
      if count[q[0]] == 0:
        heappop(q)
      ans += key * val
    else:
      key = heappop(q)
      sec_key = q[0]
      count[key] -= 1
      count[sec_key] -= 1
      if key + sec_key not in count:
        heappush(q, key + sec_key)
      count[key + sec_key] += 1
      ans += key + sec_key
      if count[sec_key] == 0:
        heappop(q)
  print(ans)

for _ in range(int(input())) :
  solve()

풀이 완료!

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.