進制轉換 題解
簡潔題意
給一個 \(A\) 進制表示的非負整數 \(x\)(\(2 \le A, B \le 36\),位數字 \(10 \sim 35\) 用大寫 A ~ Z),把它轉成 \(B\) 進制輸出。保證 \(x\) 的十進制值不超過 \(10^{18}\)。
解法
這題就是把第十五單元的兩個方向接起來:先把 \(A\) 進制字串變成整數(15.3),再把整數變成 \(B\) 進制字串(15.4)。十進制只是中繼站,程式裡就是一個 long long。
第一步用 15.3 的累積式,從最高位往下掃:
\[\texttt{val} = \texttt{val} \times A + \texttt{digit}\]字元轉數值是 8.2 的活:數字 c - '0'、字母 c - 'A' + 10。
第二步用 15.4 的「取個位、去個位」:反覆取 val % B、再 val /= B,取出的位由低到高,最後 reverse 翻回來(或倒著印)。數值轉字元同樣照 8.2:'0' + d、\(10\) 以上 'A' + (d - 10)。
兩個 15.4 講過的坑這題都在:\(x = 0\) 要特判(剝位迴圈一次都不會跑,什麼都印不出來),以及 val 要用 long long——值上看 \(10^{18}\),int 一路乘上去必溢位(上冊 2.9)。
拿範例 1 走一遍:36(十進制)讀進來是 \(36\);轉 \(36\) 進制取 \(36 \bmod 36 = 0\)、剩 \(1\),再取 \(1\)——由低到高是 0、1,翻回來就是 10。
常犯錯誤
val開int(WA):範例 3 的值就是 \(10^{18}\),讀到一半就溢位- \(x = 0\) 沒特判(WA):印出空字串
- 忘了翻轉(WA):剝位取出的順序是低位在前,範例 1 會印成
01 - 字母對映錯(WA):
A是 \(10\) 不是 \(11\);範例 2 的Z是 \(35\)
參考程式碼
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
// 進制位字元 <-> 數值(8.2)
int charToDigit(char c) {
if (c >= '0' && c <= '9') return c - '0';
return c - 'A' + 10;
}
char digitToChar(int d) {
if (d < 10) return '0' + d;
return 'A' + (d - 10);
}
int main() {
int A, B;
string s;
cin >> A >> B >> s;
long long val = 0; // 值上看 10^18:用 long long
for (int i = 0; i < (int)s.size(); i++) {
val = val * A + charToDigit(s[i]); // 15.3:舊值整體升一位,個位放新數字
}
if (val == 0) { // 15.4 的特判:0 在任何進制都是 "0"
cout << 0 << '\n';
return 0;
}
string ans;
while (val > 0) { // 15.4:取個位、去個位
ans += digitToChar(val % B);
val /= B;
}
reverse(ans.begin(), ans.end()); // 取出順序是低位在前,翻回來
cout << ans << '\n';
return 0;
}
複雜度:\(O(|x| + \text{輸出位數})\)。