INFO
1. 문제 이해
핵심 요구사항
- 36진법 숫자 N개에서 K개의 숫자를 고름 → 전체에서 그 숫자를 Z로 변경 → 다 더함
- 목적: 최댓값을 구하는 프로그램
제한 조건
- 변수 범위
- N ⇐ 50
- 수의 길이 ⇐ 50
- 0 ⇐ K ⇐ 36
- 시간: 2초
- 메모리: 128MB
BigInteger 타입 사용
- 문제에서 주어지는 36진수의 수는 최대 50자리 ⇒
Long자료형이 감당할 수 있는 수의 범위는 으로 택도 없이 부족함- 따라서
BigInteger타입을 사용해야함.
2. 사고의 흐름 (Thinking)
-
❌ 제외: 완전 탐색 (Brute Force)
- 완전탐색에서 최악의 경우: K=18
- 36개의 숫자 중에서 18개를 고르는 경우의 수만 9,075,135,300번… 절대 안됨
- 완전탐색에서 최악의 경우: K=18
-
❌ 1차 시도: 그리디 (Greedy)
- 50개 중에서 높은 자리의 숫자부터 고르거나
- 더 많이 등장하는 숫자부터 고르거나
- 동일한 경우 더 작은 숫자
- Z로 바꿨을 때 영향이 더 큰 수부터 K개 골라서 Z로 바꾸기
-
✏️ 2차 시도: 그리디 (Greedy)
- “Z로 바꿨을 때 영향이 더 큰 수부터 K개 골라서 Z로 바꾸기” 라는 방향성은 동일
- 단, 1차 시도에서 알 수 있다시피 간단하게 판단하기에는 기준이 많음
- 따라서 어떤 숫자가 가장 Z로 바뀌었을 때 가장 영향이 큰 지를 직접 구하는 방향을 채택
- 주어진 수의 각 숫자에 대해서
(Z-해당 숫자) * 자릿수를 구하고, 각 숫자 별로 누적해 더함. - 모든 수를 다 연산한 후, 더한 수 중 가장 큰 수 K개를 원래 수에 더 함.
- 주어진 수의 각 숫자에 대해서
3. 풀이 및 코드 (Solution)
import java.io.*;
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N, K;
BigInteger original = BigInteger.ZERO, result = BigInteger.ZERO;
String[] nums;
BigInteger[] weights = new BigInteger[36];
for (int i = 0; i<36; i++) {
weights[i] = BigInteger.ZERO;
}
N = Integer.parseInt(br.readLine());
nums = new String[N];
for (int n=0; n<N; n++) {
nums[n] = br.readLine();
String num36 = nums[n];
BigInteger offset = BigInteger.ONE;
for (int i=num36.length()-1; i>=0; i--) {
char c36 = num36.charAt(i);
int c10 = convertTo10(c36);
original = original.add(BigInteger.valueOf(c10).multiply(offset));
weights[c10] = weights[c10].add(BigInteger.valueOf(35 - c10).multiply(offset));
offset = offset.multiply(BigInteger.valueOf(36));
}
}
K = Integer.parseInt(br.readLine());
Arrays.sort(weights, Collections.reverseOrder());
for (int i=0; i<K; i++) {
original = original.add(weights[i]);
}
System.out.println(original.toString(36).toUpperCase());
}
static int convertTo10(char c) {
if (c >= 65) return c-'A' + 10;
else return c-'0';
}
}- 시간 복잡도:
- 수의 모든 자릿수를 다 돌기 때문에 주어지는 (수의 개수 수의 길이)이다.
- 동시에 BigInteger의 덧셈/곱셈은 자릿수에 비례하기 때문에 수의 길이를 다시 한번 곱해서 이 된다.
4. 회고 (Retrospective)
BigInteger처음 써본다. 이런게 있는지도 처음 알았다. 더 익숙해져야지- 그리디라고 어어어엄청 그리디하게 풀지는 않는 경우가 있다. 이 문제의 경우에도 변화값을 다 구하고 그중에서 최댓값을 구하는 방식이다.