POJ1220 高精度进制转换

POJ1220 高精度进制转换

思路分析

首先无论是什么进制,我们要转换成十进制的方式进行计算,因为这是高级语言提供提供的计算工具,我们必须借此进行中转。

最直观的思路自然是将输入转换成十进制,再利用短除法转换成任意进制的输出,这种想法就面临着以下两个问题:

  1. 输入转换成十进制可能会溢出,这样不仅无法直接利用内置数据类型存储并计算,在转换时还将产生很多的计算量,可能与我们开始的意愿相径庭。
  2. 十进制转换为任意进制输出时,短除法在计算时可能要处理一个溢出的十进制数,计算量也很大。

总之,计算将会涉及高精度(以前没有系统地了解过这一概念,这实际上是一类题目,在后续的博客中我将集中训练一下),以上思路在输入转十进制和十进制转输出的两步均涉及高精度,而且还是加、乘、除、取模均涉及的大整数高精度,这有点太麻烦了。

短除法的核心在于取模和取商,这一题中短除法的关键阻碍又在于高精度。高精度除了可以用模拟的方式去解决,还可以用数论的方式,用低精度的“小的数”去组装高精度的“大数”,从而求其模或者商,这一方法虽然比较难想,需要一些数学知识,但是在计算上往往不麻烦。

这一题就是如此,我们可以不用写出其十进制的完整表示,而用一系列的数相加来表示这个十进制大数。将输入的数按位转换成十进制,那么其每一个位都将有一个输入进制次幂的位权,二者相乘就得到了这一位所表示的十进制数的部分。所有位相加,就是我们要的十进制数。我们如果把这些加数中的每一个分别取余再将余数收集起来再取余,就可以得到最终整个十进制大数的余数。(这个东西好像叫做同余模定理

这里我的第一思路是先对每一位上的十进制数(乘以位权后的)取模,但是这样就会有一个问题,取模之后剩下的商没办法再用位权表示了。

于是我们就有了一个退求其次的思路,把余数留得多一些,反正最后一次要取模的余数只要还没溢出就可以。这样我们只对每一位上的数字取模,余数拿出来放到下一位加上去。从高位到低位,每一位都比下一位多一个该进制大小的基数,乘以这个基数加到下一位即可。这样一直到最后一位(最低位),累计的余数全部都在这一位,这一位还刚好就是一个不会溢出的十进制数,取模就可以了。各个位上剩下的数就是取余之后的商。重复这一操作,直到输入数变为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

第一条比较好记,第二条就把加换成乘(

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值