POJ1220 高精度进制转换
思路分析
首先无论是什么进制,我们要转换成十进制的方式进行计算,因为这是高级语言提供提供的计算工具,我们必须借此进行中转。
最直观的思路自然是将输入转换成十进制,再利用短除法转换成任意进制的输出,这种想法就面临着以下两个问题:
- 输入转换成十进制可能会溢出,这样不仅无法直接利用内置数据类型存储并计算,在转换时还将产生很多的计算量,可能与我们开始的意愿相径庭。
- 十进制转换为任意进制输出时,短除法在计算时可能要处理一个溢出的十进制数,计算量也很大。
总之,计算将会涉及高精度(以前没有系统地了解过这一概念,这实际上是一类题目,在后续的博客中我将集中训练一下),以上思路在输入转十进制和十进制转输出的两步均涉及高精度,而且还是加、乘、除、取模均涉及的大整数高精度,这有点太麻烦了。
短除法的核心在于取模和取商,这一题中短除法的关键阻碍又在于高精度。高精度除了可以用模拟的方式去解决,还可以用数论的方式,用低精度的“小的数”去组装高精度的“大数”,从而求其模或者商,这一方法虽然比较难想,需要一些数学知识,但是在计算上往往不麻烦。
这一题就是如此,我们可以不用写出其十进制的完整表示,而用一系列的数相加来表示这个十进制大数。将输入的数按位转换成十进制,那么其每一个位都将有一个输入进制次幂的位权,二者相乘就得到了这一位所表示的十进制数的部分。所有位相加,就是我们要的十进制数。我们如果把这些加数中的每一个分别取余再将余数收集起来再取余,就可以得到最终整个十进制大数的余数。(这个东西好像叫做同余模定理)
这里我的第一思路是先对每一位上的十进制数(乘以位权后的)取模,但是这样就会有一个问题,取模之后剩下的商没办法再用位权表示了。
于是我们就有了一个退求其次的思路,把余数留得多一些,反正最后一次要取模的余数只要还没溢出就可以。这样我们只对每一位上的数字取模,余数拿出来放到下一位加上去。从高位到低位,每一位都比下一位多一个该进制大小的基数,乘以这个基数加到下一位即可。这样一直到最后一位(最低位),累计的余数全部都在这一位,这一位还刚好就是一个不会溢出的十进制数,取模就可以了。各个位上剩下的数就是取余之后的商。重复这一操作,直到输入数变为0,就完成了。
代码
#include <iostream>
#include <map>
#include <stack>
using namespace std;
char dic[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int main(){
int num = 0;
cin >> num;
while (num--) {
int in_bit = 0;
int out_bit = 0;
map<char,int> m;
for(int k = 0;k < 62;k++){
m[dic[k]] = k;
}
cin >> in_bit >> out_bit;
char str[1024];
int dec[1024];
memset(dec, 0, sizeof(dec));
int i = 0;
getchar();
while ((str[i] = getchar()) != '\n') {
dec[i] = m[str[i]];
i++;
}
stack<int> res;
while(true){
for(int t = 0;t < i;t++){
dec[t+1] += ((dec[t] % out_bit) * in_bit);
dec[t] /= out_bit;
}
res.push(dec[i]/in_bit);
dec[i] = 0;
bool flg = false;
for(int p = 0;p < i;p++){
if(dec[p] != 0) flg = true;
}
if(!flg) break;
}
cout << in_bit << " ";
for(int q = 0;q < i;q++){
cout << str[q];
}
cout << endl << out_bit << " ";
while (!res.empty()) {
cout << dic[res.top()];
res.pop();
}
cout << endl << endl;
}
}
208KB 16ms
知识扩展——同余模定理
同余模定理主要有两条:
(a+b)%c=(a%c+b%c)%c
(a*b)%c=(a%c*b%c)%c
第一条比较好记,第二条就把加换成乘(