a진법으로 쓴 수 하나를 b진법으로 바꾸어 출력하라.
수는 0 이상이고, 소수점 아래가 끝없이 되풀이될 수도 있다.
되풀이되는 부분은 한 번만 쓰고 괄호로 감싼다: 10진법 0.1666…은 0.1(6), 0.142857142857…은 0.(142857)이다.
자리 값이 10 이상이면 영어 대문자를 쓴다: A = 10, B = 11, …, Z = 35.
입력의 수는 I, I.F, I.F(R) 세 꼴 가운데 하나다.
I는 정수 부분으로 한 자리 이상이며, 0 한 글자가 아니면 0으로 시작하지 않는다.
F는 소수점 바로 뒤의 되풀이되지 않는 부분으로 비어 있을 수 있고, R는 되풀이되는 부분으로 한 자리 이상이다.
소수점이 있으면 F와 R가 둘 다 비어 있지는 않다.
입력의 소수 부분은 가장 짧게 정리되어 있지 않을 수 있다: 0.50, 0.1(0), 0.12(32), 0.(9) 같은 표기도 나온다.
출력은 같은 값을 b진법으로 쓴 단 하나의 표기다.
정수 부분은 맨 앞에 쓸데없는 0을 붙이지 않는다(정수 부분이 0이면 0 한 글자).
값이 정수이면 소수점을 쓰지 않는다.
소수점 아래가 유한하면 괄호 없이 쓰고, 마지막 자리는 0이 아니다.
소수점 아래가 끝없이 이어지면, 되풀이 부분이 가장 앞에서 시작하게 하고 그중 가장 짧은 것을 괄호로 감싼다.
(b−1)이 끝없이 이어지는 표기는 쓰지 않는다: 10진법 0.(9)는 1과 같은 값이므로 1로 쓴다.
첫 줄에 a와 b가 빈칸 하나로 나뉘어, 둘째 줄에 a진법으로 쓴 수가 빈칸 없이 주어진다.
입력
2 ≤ a, b ≤ 36. 정수 부분 I의 값은 10진법으로 10⁹ 미만이다. 소수점 아래에 쓰인 자리 수(괄호 안 포함)를 d라 하면 a^d ≤ 10,000이다. 각 자리는 0~9 또는 A~Z이고 값이 a보다 작다.
출력
b진법으로 쓴 수 한 줄(대문자, 위 규칙에 맞는 단 하나의 표기)
예시 1 · stdin
10 2
0.1
stdout
0.0(0011)
예시 2 · stdin
10 6
12.4(9)
stdout
20.3
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
분수로 바꾼 뒤 긴 나눗셈을 하면 돼요. a진법 I.F(R)에서 F가 k자리, R가 m자리면 값은 p / q이고 q = a^k × (a^m − 1), p = I × q + F × (a^m − 1) + R이에요(R가 없으면 q = a^k, p = I × q + F). 이제 p를 q로 나눈 몫을 b진법으로 쓰고, 나머지 r은 r × b를 q로 나눈 몫이 다음 자리, 그 나머지가 새 r이에요. r이 0이 되면 끝나고, 앞에서 본 r이 다시 나오면 그 r로 만든 자리부터 되풀이돼요. r은 q보다 작으니 q번 안에 둘 중 하나가 일어나요. 이렇게 나누면 가장 앞에서 시작하는 가장 짧은 마디가 저절로 나오고, (b−1)이 끝없이 이어지는 표기도 나오지 않아요. 어느 r을 언제 봤는지는 Python은 사전, 나머지는 q칸짜리 배열에 적어요(q ≤ 10,000; 크레이콘은 새목록(q, -1)). 자리 읽기는 언어마다 달라요: Python int(t, a), Java Long.parseLong(t, a), JavaScript·TypeScript parseInt(t, a)는 2~36진법을 바로 읽지만 빈 F를 넣으면 Python·Java는 예외, JavaScript는 NaN이라 빈 문자열은 0으로 따로 다뤄요. C#의 Convert.ToInt64(t, base)는 2·8·10·16진법만 받아서 Digits.IndexOf(ch)로, C는 strchr(DIGITS, c) - DIGITS, C++는 DIGITS.find(ch), 크레이콘은 DIGITS.자리찾기(ch)로 자리 값을 구해요. 함정 하나: 정수 부분과 소수 부분을 따로 바꾸면 0.(9)처럼 소수 부분이 정확히 1인 수에서 깨져요. 9 / 9를 나누면 첫 자리가 10이 되어 10진법으로 0.A가 나와요. p 전체를 q로 나눠야 1이 정수 부분으로 올라가요. 함정 둘: p는 10⁹ × 10⁴ = 10¹³ 가까이 커져서 Java·C#·C·C++의 int로는 넘쳐요 — long/long long을 써요(Python은 정수에 끝이 없고, JavaScript·크레이콘은 2^53까지 정확해서 괜찮아요). 함정 셋: r의 위치는 그 r로 자리를 만들기 전에 적어야 해요. 자리를 넣은 뒤에 적으면 10진법 0.1(6)이 0.16()이 돼요. 함정 넷: r이 0이 되면 바로 멈춰야 해요. 0을 한 번 더 나누면 끝에 0이 붙어 10진법 0.5가 2진법 0.10이 돼요. 함정 다섯: 정수 부분이 0이면 while (v > 0)이 한 번도 돌지 않아 0.1이 .1이 돼요(C·C++·C# 풀이는 do-while로 막았어요). 함정 여섯: JavaScript·TypeScript v.toString(b)와 Java Long.toString(v, b)는 소문자를 내서 toUpperCase()가 필요해요. 함정 일곱: C·C++·Java·C#에서 자리 값을 c - '0'으로 구하면 'A'가 10이 아니라 17이 돼요.
Pythonmain.py · 49 줄
DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"a, b = map(int, input().split())s = input().strip()# 정수 부분 / 끝나는 부분 F / 되풀이 부분 R 로 나눈다int_str, _, frac = s.partition(".")fixed, _, rep = frac.partition("(")rep = rep.rstrip(")")# 값을 분수 p / q 로 만든다: q = a^k × (a^m − 1) (R가 없으면 a^k)k, m = len(fixed), len(rep)f_val = int(fixed, a) if fixed else 0if m == 0: q = a ** k num = f_valelse: r_val = int(rep, a) q = a ** k * (a ** m - 1) num = f_val * (a ** m - 1) + r_valp = int(int_str, a) * q + num # 소수 부분이 1이 될 수도 있으니(0.(9)) 한꺼번에 나눈다whole, r = divmod(p, q)# 정수 부분을 b진법으로head = []while True: head.append(DIGITS[whole % b]) whole //= b if whole == 0: breakout = "".join(reversed(head))# 나머지를 b배 하며 긴 나눗셈. 같은 나머지가 다시 나오면 거기서부터 되풀이된다seen = {} # 나머지 → 그 나머지로 만든 자리의 위치digits = []while r != 0 and r not in seen: seen[r] = len(digits) r *= b digits.append(DIGITS[r // q]) r %= qif digits: if r == 0: out += "." + "".join(digits) else: start = seen[r] out += "." + "".join(digits[:start]) + "(" + "".join(digits[start:]) + ")"print(out)
JavaScriptmain.js · 43 줄
const DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";const [line1, line2] = require("fs").readFileSync(0, "utf8").trim().split(/\r?\n/);const [a, b] = line1.split(" ").map(Number);const s = line2.trim();// a진법 글자들을 값으로(빈 문자열이면 0). 값은 10^13쯤이라 2^53 안이다const read = (t) => (t === "" ? 0 : parseInt(t, a));// 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다const m = s.match(/^([0-9A-Z]+)(?:\.([0-9A-Z]*)(?:\(([0-9A-Z]+)\))?)?$/);const intStr = m[1], fixed = m[2] ?? "", rep = m[3] ?? "";// 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^klet q = a ** fixed.length;let num = read(fixed);if (rep !== "") { const am1 = a ** rep.length - 1; q *= am1; num = num * am1 + read(rep);}const p = read(intStr) * q + num; // 소수 부분이 1일 수도 있으니(0.(9)) 한꺼번에 나눈다let out = Math.floor(p / q).toString(b).toUpperCase(); // toString은 소문자를 낸다let r = p % q;// 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다const seen = new Array(q).fill(-1); // 나머지 → 그 나머지로 만든 자리의 위치const digits = [];while (r !== 0 && seen[r] === -1) { seen[r] = digits.length; r *= b; digits.push(DIGITS[Math.floor(r / q)]); r %= q;}if (digits.length > 0) { if (r === 0) out += "." + digits.join(""); else { const start = seen[r]; out += "." + digits.slice(0, start).join("") + "(" + digits.slice(start).join("") + ")"; }}console.log(out);
TypeScriptmain.ts · 46 줄
import { readFileSync } from "node:fs";const DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";const [line1, line2] = readFileSync(0, "utf8").trim().split(/\r?\n/);const [a, b]: number[] = line1.split(" ").map(Number);const s: string = line2.trim();// a진법 글자들을 값으로(빈 문자열이면 0). 값은 10^13쯤이라 2^53 안이다const read = (t: string): number => (t === "" ? 0 : parseInt(t, a));// 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다const m = s.match(/^([0-9A-Z]+)(?:\.([0-9A-Z]*)(?:\(([0-9A-Z]+)\))?)?$/)!;const intStr: string = m[1];const fixed: string = m[2] ?? "";const rep: string = m[3] ?? "";// 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^klet q: number = a ** fixed.length;let num: number = read(fixed);if (rep !== "") { const am1 = a ** rep.length - 1; q *= am1; num = num * am1 + read(rep);}const p: number = read(intStr) * q + num; // 소수 부분이 1일 수도 있으니(0.(9)) 한꺼번에 나눈다let out: string = Math.floor(p / q).toString(b).toUpperCase(); // toString은 소문자를 낸다let r: number = p % q;// 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다const seen: number[] = new Array<number>(q).fill(-1); // 나머지 → 그 나머지로 만든 자리의 위치const digits: string[] = [];while (r !== 0 && seen[r] === -1) { seen[r] = digits.length; r *= b; digits.push(DIGITS[Math.floor(r / q)]); r %= q;}if (digits.length > 0) { if (r === 0) out += "." + digits.join(""); else { const start = seen[r]; out += "." + digits.slice(0, start).join("") + "(" + digits.slice(start).join("") + ")"; }}console.log(out);
JavaMain.java · 71 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.Arrays;public class Main { static final String DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // a진법 글자들을 값으로(빈 문자열이면 0) static long read(String t, int a) { return t.isEmpty() ? 0 : Long.parseLong(t, a); } public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] ab = in.readLine().trim().split(" "); int a = Integer.parseInt(ab[0]), b = Integer.parseInt(ab[1]); String s = in.readLine().trim(); // 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다 String intStr = s, fixed = "", rep = ""; int dot = s.indexOf('.'); if (dot >= 0) { intStr = s.substring(0, dot); String frac = s.substring(dot + 1); int open = frac.indexOf('('); if (open >= 0) { fixed = frac.substring(0, open); rep = frac.substring(open + 1, frac.length() - 1); } else { fixed = frac; } } // 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^k long q = 1; for (int i = 0; i < fixed.length(); i++) q *= a; long num = read(fixed, a); if (!rep.isEmpty()) { long am1 = 1; for (int i = 0; i < rep.length(); i++) am1 *= a; am1 -= 1; q *= am1; num = num * am1 + read(rep, a); } long p = read(intStr, a) * q + num; // 10^13까지 커지니 long. 소수 부분이 1일 수도 있어 한꺼번에 나눈다 StringBuilder out = new StringBuilder(Long.toString(p / q, b).toUpperCase()); // toString은 소문자를 낸다 int r = (int) (p % q); // q < 10000이라 나머지는 int에 들어간다 // 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다 int[] seen = new int[(int) q]; // 나머지 → 그 나머지로 만든 자리의 위치 Arrays.fill(seen, -1); StringBuilder digits = new StringBuilder(); while (r != 0 && seen[r] == -1) { seen[r] = digits.length(); r *= b; digits.append(DIGITS.charAt((int) (r / q))); r %= q; } if (digits.length() > 0) { out.append('.'); if (r == 0) out.append(digits); else { int start = seen[r]; out.append(digits, 0, start).append('(').append(digits, start, digits.length()).append(')'); } } System.out.println(out); }}
C#Main.cs · 86 줄
using System;using System.Text;class Program{ const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // a진법 글자들을 값으로(빈 문자열이면 0). Convert.ToInt64(s, base)는 2·8·10·16진법만 받는다 static long Read(string t, int a) { long v = 0; foreach (char ch in t) v = v * a + Digits.IndexOf(ch); return v; } static void Main() { string[] ab = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); int a = int.Parse(ab[0]), b = int.Parse(ab[1]); string s = Console.ReadLine().Trim(); // 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다 string intStr = s, fixedPart = "", rep = ""; int dot = s.IndexOf('.'); if (dot >= 0) { intStr = s[..dot]; string frac = s[(dot + 1)..]; int open = frac.IndexOf('('); if (open >= 0) { fixedPart = frac[..open]; rep = frac[(open + 1)..^1]; } else fixedPart = frac; } // 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^k long q = 1; for (int i = 0; i < fixedPart.Length; i++) q *= a; long num = Read(fixedPart, a); if (rep.Length > 0) { long am1 = 1; for (int i = 0; i < rep.Length; i++) am1 *= a; am1 -= 1; q *= am1; num = num * am1 + Read(rep, a); } long p = Read(intStr, a) * q + num; // 10^13까지 커지니 long. 소수 부분이 1일 수도 있어 한꺼번에 나눈다 long whole = p / q; var head = new StringBuilder(); do { head.Insert(0, Digits[(int)(whole % b)]); // 낮은 자리부터 나오니 앞에 끼운다 whole /= b; } while (whole > 0); long r = p % q; // 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다 int[] seen = new int[q]; // 나머지 → 그 나머지로 만든 자리의 위치 Array.Fill(seen, -1); var digits = new StringBuilder(); while (r != 0 && seen[r] == -1) { seen[r] = digits.Length; r *= b; digits.Append(Digits[(int)(r / q)]); r %= q; } var outSb = new StringBuilder(head.ToString()); if (digits.Length > 0) { string d = digits.ToString(); if (r == 0) outSb.Append('.').Append(d); else { int start = seen[r]; outSb.Append('.').Append(d[..start]).Append('(').Append(d[start..]).Append(')'); } } Console.WriteLine(outSb); }}
C++main.cpp · 79 줄
#include <iostream>#include <string>#include <vector>#include <algorithm>const std::string DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";// a진법 글자들을 값으로(빈 문자열이면 0)long long readPart(const std::string &t, int a) { long long v = 0; for (char ch : t) v = v * a + (long long)DIGITS.find(ch); return v;}long long power(int a, std::size_t k) { long long v = 1; for (std::size_t i = 0; i < k; i++) v *= a; return v;}int main() { int a, b; std::string s; std::cin >> a >> b >> s; // 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다 std::string intStr = s, fixed, rep; auto dot = s.find('.'); if (dot != std::string::npos) { intStr = s.substr(0, dot); std::string frac = s.substr(dot + 1); auto open = frac.find('('); if (open != std::string::npos) { fixed = frac.substr(0, open); rep = frac.substr(open + 1, frac.size() - open - 2); } else { fixed = frac; } } // 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^k long long q = power(a, fixed.size()); long long num = readPart(fixed, a); if (!rep.empty()) { long long am1 = power(a, rep.size()) - 1; q *= am1; num = num * am1 + readPart(rep, a); } long long p = readPart(intStr, a) * q + num; // 10^13까지 커지니 long long long long whole = p / q; // 소수 부분이 1일 수도 있으니(0.(9)) 한꺼번에 나눈다 std::string out; do { out += DIGITS[whole % b]; whole /= b; } while (whole > 0); std::reverse(out.begin(), out.end()); // 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다 std::vector<int> seen(q, -1); // 나머지 → 그 나머지로 만든 자리의 위치 std::string digits; long long r = p % q; while (r != 0 && seen[r] == -1) { seen[r] = (int)digits.size(); r *= b; digits += DIGITS[r / q]; r %= q; } if (!digits.empty()) { out += '.'; if (r == 0) out += digits; else { int start = seen[r]; out += digits.substr(0, start) + "(" + digits.substr(start) + ")"; } } std::cout << out << '\n';}
Cmain.c · 76 줄
#include <stdio.h>#include <string.h>static const char *DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";/* s[from..to) 의 a진법 글자들을 값으로(비어 있으면 0) */static long long read_part(const char *s, int from, int to, int a) { long long v = 0; for (int i = from; i < to; i++) v = v * a + (long long)(strchr(DIGITS, s[i]) - DIGITS); /* 'A'는 10: c - '0'이 아니다 */ return v;}static long long power(int a, int k) { long long v = 1; while (k-- > 0) v *= a; return v;}int main(void) { int a, b; char s[128]; if (scanf("%d %d %127s", &a, &b, s) != 3) return 0; int len = (int)strlen(s); /* 정수 부분 [0, dot) / 끝나는 부분 [dot+1, open) / 되풀이 부분 [open+1, len-1) */ char *pdot = strchr(s, '.'); int dot = pdot ? (int)(pdot - s) : len; char *popen = strchr(s, '('); int open = popen ? (int)(popen - s) : len; int fixed_from = dot < len ? dot + 1 : len; /* 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^k */ long long q = power(a, open - fixed_from); long long num = read_part(s, fixed_from, open, a); if (open < len) { long long am1 = power(a, len - 1 - (open + 1)) - 1; q *= am1; num = num * am1 + read_part(s, open + 1, len - 1, a); } long long p = read_part(s, 0, dot, a) * q + num; /* 10^13까지 커지니 long long */ long long whole = p / q; /* 소수 부분이 1일 수도 있으니(0.(9)) 한꺼번에 나눈다 */ char head[64]; int hl = 0; do { head[hl++] = DIGITS[whole % b]; whole /= b; } while (whole > 0); for (int i = hl - 1; i >= 0; i--) putchar(head[i]); /* 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다 */ static int seen[10000]; /* 나머지 → 그 나머지로 만든 자리의 위치 */ static char digits[10001]; for (int i = 0; i < q; i++) seen[i] = -1; int n = 0; long long r = p % q; while (r != 0 && seen[r] == -1) { seen[r] = n; r *= b; digits[n++] = DIGITS[r / q]; r %= q; } digits[n] = '\0'; if (n > 0) { putchar('.'); if (r == 0) fputs(digits, stdout); else { int start = seen[r]; printf("%.*s(%s)", start, digits, digits + start); } } putchar('\n'); return 0;}
Craykonmain.cray · 99 줄
DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";// a진법 글자들을 앞에서부터 읽어 값으로 만든다(빈 문자열이면 0)읽기(s, a){ v = 0; 각각 (ch 에서 s) { v = v * a + DIGITS.자리찾기(ch); } 돌려주기 v;}거듭(a, k){ v = 1; 반복 (i = 0; i < k; i += 1) { v = v * a; } 돌려주기 v;}ab = 콘솔.수들읽기();a = ab[0];b = ab[1];s = 콘솔.줄읽기().공백제거();// 정수 부분 / 끝나는 부분 / 되풀이 부분으로 나눈다intStr = s;fixed = "";rep = "";dot = s.자리찾기(".");만약 (dot >= 0){ intStr = s.부분문자열(0, dot); frac = s.부분문자열(dot + 1); open = frac.자리찾기("("); 만약 (open >= 0) { fixed = frac.부분문자열(0, open); rep = frac.부분문자열(open + 1, frac.길이 - open - 2); } 아니면 { fixed = frac; }}// 값을 분수 p / q 로: q = a^k × (a^m − 1), 되풀이 부분이 없으면 a^kq = 거듭(a, fixed.길이);num = 읽기(fixed, a);만약 (rep.길이 > 0){ am1 = 거듭(a, rep.길이) - 1; q = q * am1; num = num * am1 + 읽기(rep, a);}p = 읽기(intStr, a) * q + num; // 소수 부분이 1일 수도 있으니(0.(9)) 한꺼번에 나눈다whole = 수학.몫(p, q);r = p % q;// 정수 부분을 b진법으로out = "";동안 (참){ out = DIGITS[whole % b] + out; whole = 수학.몫(whole, b); 만약 (whole == 0) { 그만; }}// 긴 나눗셈: 같은 나머지가 다시 나오면 거기서부터 되풀이된다seen = 새목록(q, -1); // 나머지 → 그 나머지로 만든 자리의 위치digits = [];동안 (r != 0 && seen[r] == -1){ seen[r] = digits.개수; r = r * b; digits.넣기(DIGITS[수학.몫(r, q)]); r = r % q;}만약 (digits.개수 > 0){ 만약 (r == 0) { out = out + "." + digits.잇기(""); } 아니면 { start = seen[r]; out = out + "." + digits.부분목록(0, start).잇기("") + "(" + digits.부분목록(start, digits.개수 - start).잇기("") + ")"; }}콘솔.쓰기(out);