각 자릿값(0~35)을 Z(35)로 바꿀 때 합의 증가량을 미리 계산하고, 이득이 큰 K개를 그리디로 선택.
처음에는 실제 교체 후 합을 다시 구하려 했으나, "이득 합산" 방식이 훨씬 단순함을 파악.
각 36진수 문자열을 10진수 BigInteger로 변환 후 합산.
"A3Z" → 10×36² + 3×36¹ + 35×36⁰ = 12960 + 108 + 35 = 13103
Horner's method 활용:
BigInteger val = BigInteger.ZERO;
for (char c : num.toCharArray()) {
val = val.multiply(BASE).add(BigInteger.valueOf(getValue(c)));
}
digit d를 Z(35)로 바꾸면 해당 위치마다 (35 - d) × 36^pos 증가.
"A3Z"에서 '3'(d=3)을 Z로 바꿀 때 이득:
pos = 1 → (35 - 3) × 36¹ = 32 × 36 = 1152
N개 숫자 전체를 순회하며 digit별로 이득 누적:
int pos = len - 1 - i;
BigInteger placeValue = BASE.pow(pos);
gain[d] = gain[d].add(BigInteger.valueOf(35 - d).multiply(placeValue));
gain[0..35]를 정렬 후 가장 큰 K개를 원래 합에 더함.
gain = [0, 0, ..., 1152, ..., 0]
↑ Z(35)는 0 ↑ 3번 digit의 이득
Arrays.sort(gain) → 오름차순
상위 K개 = gain[35], gain[34], ..., gain[36-K]
최종 합계를 36으로 반복 나눠 나머지를 문자로 변환 후 역순 조합.
13103 ÷ 36 = 363 나머지 35 → 'Z'
363 ÷ 36 = 10 나머지 3 → '3'
10 ÷ 36 = 0 나머지 10 → 'A'
→ 역순: "A3Z"
static String to36(BigInteger n) {
if (n.equals(BigInteger.ZERO)) return "0";
StringBuilder sb = new StringBuilder();
while (n.compareTo(BigInteger.ZERO) > 0) {
int r = n.mod(BASE).intValue();
sb.append(r < 10 ? (char)('0' + r) : (char)('A' + r - 10));
n = n.divide(BASE);
}
return sb.reverse().toString();
}
BigInteger[] gain = new BigInteger[36];
Arrays.fill(gain, BigInteger.ZERO);
for (String num : nums) {
int len = num.length();
for (int i = 0; i < len; i++) {
int d = getValue(num.charAt(i));
int pos = len - 1 - i;
BigInteger placeValue = BASE.pow(pos);
gain[d] = gain[d].add(BigInteger.valueOf(35 - d).multiply(placeValue));
}
}
Arrays.sort(gain);
for (int i = 0; i < K; i++) {
sum = sum.add(gain[35 - i]);
}
O(N × L × log L)BASE.pow(pos) 연산이 자리수에 비례O(N × L)구현 자체보다 출력 형식을 놓쳐서 한 번 막혔습니다. 합계를 구한 뒤 그대로 출력하면 10진수가 나오는데, 문제에서 36진수로 출력을 요구한다는 걸 뒤늦게 깨달았습니다. 그리고 숫자가 50자리 × 1000개 규모이므로 long이 아닌 BigInteger가 반드시 필요한데, 처음에 스케일 감이 없어서 지나칠 뻔했습니다.
package B1036;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
public class Main {
static int N;
static String[] nums;
static int K;
static final BigInteger BASE = BigInteger.valueOf(36);
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
nums = new String[N];
for (int i = 0; i < N; i++) {
nums[i] = br.readLine();
}
K = Integer.parseInt(br.readLine());
BigInteger sum = BigInteger.ZERO;
for (String num : nums) {
BigInteger val = BigInteger.ZERO;
for (char c : num.toCharArray()) {
val = val.multiply(BASE).add(BigInteger.valueOf(getValue(c)));
}
sum = sum.add(val);
}
BigInteger[] gain = new BigInteger[36];
Arrays.fill(gain, BigInteger.ZERO);
for (String num : nums) {
int len = num.length();
for (int i = 0; i < len; i++) {
int d = getValue(num.charAt(i));
int pos = len - 1 - i;
BigInteger placeValue = BASE.pow(pos);
gain[d] = gain[d].add(BigInteger.valueOf(35 - d).multiply(placeValue));
}
}
Arrays.sort(gain);
for (int i = 0; i < K; i++) {
sum = sum.add(gain[35 - i]);
}
System.out.println(to36(sum));
}
static String to36(BigInteger n) {
if (n.equals(BigInteger.ZERO)) {
return "0";
}
StringBuilder sb = new StringBuilder();
while (n.compareTo(BigInteger.ZERO) > 0) {
int r = n.mod(BASE).intValue();
sb.append(r < 10 ? (char) ('0' + r) : (char) ('A' + r - 10));
n = n.divide(BASE);
}
return sb.reverse().toString();
}
static int getValue(char c) {
return c >= '0' && c <= '9' ? c - '0' : c - 'A' + 10;
}
}