NENU进制转换课后练习题解(问题A~问题F)


前言:对整数进制转换的理解

1.1进制理解

数制:也称为计数制,是一种计数的方法,是用一组固定的符号和统一的规则来表示数值的方法。在计数过程中采用进位的方法称为进位计数制(进制),包括数位、基数和位权三个要素。

数位:指数字符号在一个数中所处的位置。
基数:指在某种进位计数制中数位上所能使用的数字符号的个数。例如十进制的基数为10。
位权:数制中某一位上的1所表示数值的大小(所处位置的价值)。例如十进制的231,2的位权是100,3的位权是10,1的位权是1。

以2进制下的10011111为例:

首先10011111为二进制数,它的基数是2。那么计算位权的时候位权的底数是2。

数字10011111
数位87654321
位权 2 7 2^{7} 27 2 6 2^{6} 26 2 5 2^{5} 25 2 4 2^{4} 24 2 3 2^{3} 23 2 2 2^{2} 22 2 1 2^{1} 21 2 0 2^{0} 20

1.2如何转换?

1.2.1通法:

将b进制下的数转换为十进制下的数,再转换为目标进制下的数。

例如:
10011111十进制表示是: 1 ∗ 2 7 + 0 ∗ 2 6 + 0 ∗ 2 5 + 1 ∗ 2 4 + 1 ∗ 2 3 + 1 ∗ 2 2 + 1 ∗ 2 1 + 1 ∗ 2 0 = 159 1*2^{7}+0*2^{6}+0*2^{5}+1*2^{4}+1*2^{3}+1*2^{2}+1*2^{1}+1*2^{0}=159 127+026+025+124+123+122+121+120=159
再将其转换为7进制下的数:

步骤被除数余数
1159225
22231
3303

注意商和被除数的更迭。

将余数反序记录为:315
即为所求7进制下的表示。
1.2.1特别转换
二进制、八进制、十六进制由于 2 3 = 8 2^{3}=8 23=8 2 4 = 16 2^{4}=16 24=16的特殊关系,可以将二进制下的数从末位按三位一组(八进制)或四位一组(十六进制)直接进行转换对应的数字符。对应关系可参考下表:

二进制八进制十六进制十进制
0000
1111
10222
11333
100444
101555
110666
111777
1000/88
1001/99
1010/A10
1011/B11
1100/C12
1101/D13
1110/E14
1111/F15


问题 A: 5201 二进制位

题目描述

给定你一个十进制数n(0 < n < 1000),要求输出其二进制数。

输入

输入有多行,每行包括一个十进制的正整数n。

输出

输出对应的二进制数。

样例输入

1
2
3

样例输出

1
10
11

解析
思路梳理

读入数据后记录每次对2取的余数,并反序输出。

细节提示

reverse()函数可以用于

  1. 翻转数组:reverse(a,a+n);
  2. 翻转字符串:reverse(str.begin(),str.end());
  3. 翻转向量:reverse(vec.begin(), vec.end());

参考代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        string s0;
        while(n>1){
            s0 += to_string(n % 2);
            n /= 2;
        }
        reverse(s0.begin(), s0.end());
        cout << n << s0 << endl;
    }

    return 0;
}


问题 B: 5202 二进制转化为十六进制

题目描述

输入一个2进制的数,要求输出该2进制数的16进制表示。在16进制的表示中,A-F表示10-15。

输入

第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个以0和1组成的字符串,字符串长度至少是1,至多是10000。

输出

n行,每行输出对应一个输入。

样例输入

2
100000
111

样例输出

20
7

解析
思路梳理

2进制转16进制可以以四位为一组进行转换。

细节提示

考虑到二进制数的长度至多有1000位,我们需要以字符串形式输入。且以四位为一组时应该从最右位开始分组。

参考代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin >> n;
    while(n--){
        string num, s0, res;
        cin >> num;
        while(num.length()>=4){
            s0 = num.substr(num.length() - 4, 4);
            num = num.substr(0, num.length() - 4);
            int nx = (s0[0] - '0') * 8 + (s0[1] - '0') * 4 + (s0[2] - '0') * 2 + (s0[3] - '0');
            if(nx<10)
                res += to_string(nx);
            else
                res.push_back(char(nx - 10 + 'A'));
        }
        reverse(res.begin(), res.end());
        if(num.length()==0)
            cout << res;
        else if (num.length() == 1)
            cout << num << res;
        else if(num.length() == 2)
            cout << (num[0] - '0') * 2 + (num[1] - '0') << res;
        else if(num.length()==3)
            cout << (num[0] - '0') * 4 + (num[1] - '0')*2+(num[2]-'0') << res;
        cout << endl;
    }

    return 0;
}


问题 C: 5203 周易II

题目描述

有人说,中国古代的“周易”是二进制系统的起源,在该系统中,他们用“- -”表示1,“—”表示0。因此,二进制数字“011010”可以表述为“—\n- -\n- -\n—\n- -\n—\n”(符号“\n”表示换行)。现在的问题是如何把一个“周易”中的二进制转换为相应的十进制数?

输入

文件中包含多组测试数据。每个测试数据都是以一个数字k (0 < k <= 20)开始,表示这个数在二进制中的位数。接下来就是k行,就是字符串—或- -,第1位表示最高位。

输出

对于每组测试数据,输出对应的十进制数。

样例输入

3
- -
- -
- -
3
---
---
---
6
---
- -
- -
---
- -
---

样例输出

7
0
26

解析
思路梳理

这题比较简单,思路和问题A差不多,比问题A还简单一些。

细节提示

实际进行数据测试时,如果直接使用st.compare("---")==0来判断字符会无法通过,可能是测试点中并不是每行都是---或者- -,但是前三个字符一定是符合的,所以建议使用st[0]=='-'&&st[1]=='-'&&st[2]=='-'判断。
getline和get输入行为比较(来自c++ primer plus第六版 中文版)

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 30;
int nx[N];
int main(){
    int n;
    while(scanf("%d ",&n)!=EOF){//多扫描一个空格避免换行存在
        int i = 0;
        while(n--){
            string st;
            getline(cin, st);
            if (st[0]=='-'&&st[1]=='-'&&st[2]=='-')
                nx[i++] = 0;
            else if(st[0]=='-'&&st[1]==' '&&st[2]=='-')
                nx[i++] = 1;
        }
        if(i>=1){
            long long ind = 1, res = 0;
            for (i-=1; i >= 0;i--){
                res += ind * nx[i];
                ind *= 2;
            }
            cout << res << endl;
        }
        else if(i==0)
            cout << 0 << endl;
    }
    return 0;
}


问题 D: 5204 二进制数

题目描述

给定一个正整数n,要求输出对应的二进制数中所有数码“1”的位置。注意最低位为第0位。例如13的二进制形式为1101,因此数码1的位置为:0,2,3。

输入

输入文件中的第1行为一个正整数d,表示输入文件中测试数据的个数,1<=d<=10,接下来有d个测试数据。每个测试数据占一行,只有一个整数n,1<=n<= 106。

输出

输出包括d行,即对输入文件中的每个测试数据,输出一行。第i行,1 <= i <= d,以升序的顺序输出第i个测试数据中的整数的二进制形式中所有数码1的位置,位置之间有1个空格,最后一个位置后面没有空格。

样例输入

2
13
127

样例输出

0 2 3
0 1 2 3 4 5 6

解析
思路梳理
先用n%2判断二进制位上是否是1,若是则输出此时的i值,i表示数位,每次进行n/=2后均增加1。
细节提示
注意最后一个数没有空格。

参考代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int d;
    cin >> d;
    while(d--){
        int n;
        cin >> n;
        int i = 0;
        while(n>0){
            int flag = 0;
            if(n%2==1){
                cout << i;
                flag = 1;
            }
            n /= 2;
            i++;
            if(n!=0&&flag)
                cout << " ";
        }
        cout << endl;
    }

    return 0;
}


问题 E: 5205 留下最少

题目描述

给定一个基数b,和b进制下的两个非负整数p和m,计算p%m,并输出b进制下的结果。p%m的结果被定义为非负整数k,要求k是满足p=a * m + k中的最小值(a为某些整数)。

输入

输入包含多组测试数据。每个测试数据占一行,由3个无符号的整数构成,第一个整数为b,一个介于2到10之间的十进制数。第二个为p,可能由1000位的0到b-1构成。第三位是m,由9位0到b-1构成。
最后一个测试数据为0,表示输入结束。

输出

对应每组测试数据,要求输出一行b进制下的p%m。

样例输入

2 1100 101
10 123456789123456789123456789 1000
0

样例输出

10
789

解析
思路梳理
由描述易知,m的值较小,可以用整型储存,所以可以直接定义一个长整型mx来作为m的数值。
利用定理:
( a + b ) m o d c = ( a m o d c + b m o d c ) m o d c ( a p ) m o d c = ( ( a m o d c ) p ) m o d c ( a ∗ b ) m o d c = ( a m o d c ∗ b m o d c ) m o d c (a+b)modc=(amodc+bmodc)modc\\ (a^p)mod c=((a mod c)^p)mod c\\ (a*b)mod c=(amodc*bmodc)mod c (a+b)modc=(amodc+bmodc)modc(ap)modc=((amodc)p)modc(ab)modc=(amodcbmodc)modc
假如数p表示为561417,进制为8。则p的十进制表示为
5 ∗ 8 5 + 6 ∗ 8 4 + 1 ∗ 8 3 + 4 ∗ 8 2 + 1 ∗ 8 1 + 7 ∗ 8 0 = 189199 5*8^{5}+6*8^{4}+1*8^{3}+4*8^{2}+1*8^{1}+7*8^{0}=189199 585+684+183+482+181+780=189199
假设是对5取余数,此时有

  • (561417)8= ( 5 ∗ 8 5 + 6 ∗ 8 4 + 1 ∗ 8 3 + 4 ∗ 8 2 + 1 ∗ 8 1 + 7 ∗ 8 0 ) m o d 5 (5*8^{5}+6*8^{4}+1*8^{3}+4*8^{2}+1*8^{1}+7*8^{0})mod5 (585+684+183+482+181+780)mod5
  • = ( ( 5 ∗ 8 5 ) m o d 5 + ( 6 ∗ 8 4 ) m o d 5 + ( 1 ∗ 8 3 ) m o d 5 + ( 4 ∗ 8 2 ) m o d 5 + ( 1 ∗ 8 1 ) m o d 5 + ( 7 ∗ 8 0 ) m o d 5 ) m o d 5 ((5*8^{5})mod5+(6*8^{4})mod5+(1*8^{3})mod5+(4*8^{2})mod5+(1*8^{1})mod5+(7*8^{0})mod5)mod5 ((585)mod5+(684)mod5+(183)mod5+(482)mod5+(181)mod5+(780)mod5)mod5
  • = ( 5 m o d 5 ∗ ( 8 m o d 5 ) 5 m o d 5 ) m o d 5 + ( 6 m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 ) m o d 5 + ( 1 m o d 5 ∗ ( 8 m o d 5 ) 3 m o d 5 ) m o d 5 + ( 4 ∗ 8 2 m o d 5 ) m o d 5 + ( 1 ∗ 8 1 m o d 5 ) m o d 5 + ( 7 m o d 5 ∗ ( 8 m o d 5 ) 0 m o d 5 ) m o d 5 ) m o d 5 (5mod5*(8mod5)^{5}mod5)mod5+(6mod 5*(8mod5)^{4}mod5)mod5+(1mod5*(8mod5)^{3}mod5)mod5+(4*8^{2}mod5)mod5+(1*8^{1}mod5)mod5+(7mod5*(8mod5)^{0}mod5)mod5)mod5 (5mod5(8mod5)5mod5)mod5+(6mod5(8mod5)4mod5)mod5+(1mod5(8mod5)3mod5)mod5+(482mod5)mod5+(181mod5)mod5+(7mod5(8mod5)0mod5)mod5)mod5

这步之后我们先看前两位

  • = ( 5 m o d 5 ∗ ( 8 m o d 5 ) 5 m o d 5 + 6 m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 ) m o d 5 + . . . (5mod5*(8mod5)^{5}mod5+6mod 5*(8mod5)^{4}mod5)mod5+... (5mod5(8mod5)5mod5+6mod5(8mod5)4mod5)mod5+...
  • = ( 5 m o d 5 ∗ 8 m o d 5 + 6 m o d 5 ) m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 ) m o d 5 + . . . (5mod5*8mod5+6mod 5)mod5*(8mod5)^{4}mod5)mod5+... (5mod58mod5+6mod5)mod5(8mod5)4mod5)mod5+...
  • = ( 5 m o d 5 ∗ 8 + 6 ) m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 + . . . (5mod5*8+6)mod5*(8mod5)^{4}mod5+... (5mod58+6)mod5(8mod5)4mod5+...

此时可以看出结果了:前 i − 1 i-1 i1位向前 i i i位转换时,只需要对上一个状态( 5 m o d 5 5mod5 5mod5的状态)乘上一个进制,再加上下一位,不断取模即可。
我们继续转换:

  • = ( 5 m o d 5 ∗ 8 + 6 ) m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 + ( 1 m o d 5 ∗ ( 8 m o d 5 ) 3 m o d 5 ) m o d 5 + . . . (5mod5*8+6)mod5*(8mod5)^{4}mod5+(1mod5*(8mod5)^{3}mod5)mod5+... (5mod58+6)mod5(8mod5)4mod5+(1mod5(8mod5)3mod5)mod5+...
  • = ( ( 5 m o d 5 ∗ 8 + 6 ) m o d 5 ∗ ( 8 m o d 5 ) 4 m o d 5 + ( 1 m o d 5 ∗ ( 8 m o d 5 ) 3 m o d 5 ) ) m o d 5 + . . . ((5mod5*8+6)mod5*(8mod5)^{4}mod5+(1mod5*(8mod5)^{3}mod5))mod5+... ((5mod58+6)mod5(8mod5)4mod5+(1mod5(8mod5)3mod5))mod5+...
  • = ( ( 5 m o d 5 ∗ 8 + 6 ) m o d 5 ∗ ( 8 m o d 5 ) + 1 m o d 5 ) m o d 5 ∗ ( ( 8 m o d 5 ) 3 m o d 5 ) m o d 5 + . . . ((5mod5*8+6)mod5*(8mod5)+1mod5)mod5*((8mod5)^{3}mod5)mod5+... ((5mod58+6)mod5(8mod5)+1mod5)mod5((8mod5)3mod5)mod5+...
  • = ( ( ( 5 m o d 5 ∗ 8 + 6 ) ∗ 8 m o d 5 ) + 1 m o d 5 ) m o d 5 ∗ ( 8 m o d 5 ) 3 m o d 5 + . . . (((5mod5*8+6)*8mod5)+1mod5)mod5*(8mod5)^{3}mod5+... (((5mod58+6)8mod5)+1mod5)mod5(8mod5)3mod5+...
  • =…
    最后会处理到 1 m o d 5 1mod5 1mod5,这个结果是1,也就直接被忽略了。
  • = ( . . . . ) ∗ ( 8 m o d 5 ) 0 m o d 5 (....)*(8mod5)^{0}mod5 (....)(8mod5)0mod5
  • = ( . . . . ) ∗ 1 m o d 5 (....)*1mod5 (....)1mod5
  • = ( . . . . ) m o d 5 (....)mod5 (....)mod5

也就是说,一个任意进制的数对x取余的结果等于其各个数位上的数(转化进制之后),对x取余的结果的和,再对x取余。
利用这一点,我们可以依次对数p的各个位置上的数进行取余,并与上一次取余运算结果构成两位的新数,乘上进制之后相加,再取余。也就是代码段

long long px = 0;
for (int i = 0; i < p.length();i++){
    px = px * b + p[i] - '0';	// 还原两位
    px %= mx;	// 计算这两位的取模结果
}

的处理方式。
细节提示
注意输出时假如结果的px为0时的输出。

参考代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int b;
    string p, m;
    while(cin>>b){
        if (b == 0)
            break;
        else{
            cin >> p >> m;
            long long mx = 0;
            for (int i = 0; i < m.length();i++)
                mx = mx * b + m[i] - '0';
            long long px = 0;
            for (int i = 0; i < p.length();i++){
                px = px * b + p[i] - '0';
                px %= mx;
            }
            if(px==0)
                cout << 0 << endl;
            else{
                string ans;
                while(px>0){
                    ans += to_string(px % b);
                    px /= b;
                }
                reverse(ans.begin(), ans.end());
                cout << ans << endl;
            }
        }
    }

    return 0;
}


问题 F: 5206 进制转换

题目描述

编写程序,实现将一个数从一种进制转换到另一种进制。在这些进制中,可以出现的数码有62个:{0-9,A-Z,a-z}。

输入

输入文件的第1行是一个正整数N,表示测试数据的个数,接下来有N行,每行的格式为:输入数据的进制(用十进制表示),输出数据的进制(用十进制表示),最后一个是用输入数据的进制所表示的数。输入/输出数据的进制范围是262,也就是说AZ相当于十进制中的1035,az相当于十进制中的36~61。

输出

对每个测试数据,程序输出3行,第1行是输入数据的进制,空格,然后是在该进制下的输入数据;第2行是输出数据的进制,空格,然后是在该进制下的输出数据;第3行为空行。

样例输入

8
62 2 abcdefghiz
10 16 1234567890123456789012345678901234567890
16 35 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2
35 23 333YMHOUE8JPLT7OX6K9FYCQ8A
23 49 946B9AA02MI37E3D3MMJ4G7BL2F05
49 61 1VbDkSIMJL3JjRgAdlUfcaWj
61 5 dl9MDSWqwHjDnToKcsWE1S
5 10 42104444441001414401221302402201233340311104212022133030

样例输出

62 abcdefghiz
2 11011100000100010111110010010110011111001001100011010010001

10 1234567890123456789012345678901234567890
16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2

16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2
35 333YMHOUE8JPLT7OX6K9FYCQ8A

35 333YMHOUE8JPLT7OX6K9FYCQ8A
23 946B9AA02MI37E3D3MMJ4G7BL2F05

23 946B9AA02MI37E3D3MMJ4G7BL2F05
49 1VbDkSIMJL3JjRgAdlUfcaWj

49 1VbDkSIMJL3JjRgAdlUfcaWj
61 dl9MDSWqwHjDnToKcsWE1S

61 dl9MDSWqwHjDnToKcsWE1S
5 42104444441001414401221302402201233340311104212022133030

5 42104444441001414401221302402201233340311104212022133030
10 1234567890123456789012345678901234567890

解析
思路梳理
此题数据都比较大,建议按字符串输入后直接用数组储存各个位置上的数值大小。

核心代码
核心代码是通过模仿整除法的步骤来进行更迭循获得结果的。

        int k, val = 1;
        //定义一个val并赋值为1,赋值为1以保证进入while循环
        //val用于记录记录数据的数组nx中数位数值的和
        string ans;//ans用于记录每次除法的余数
        while (val != 0){
            val = 0;
            int nut = 0;//nut用于取从高位起的用来做除法的数。
            k = 0;
            nut = 0;
            for (i = 0; i < len;){
                nut = nut * in + nx[i++];
                //nut需要加上从上一次除法结束时的商再做除法。
                nx[k++] = nut / ot;
                //nx进行数据重置,新填入的数是整个原数做除法之后的商。
                val += nx[k - 1];
                nut %= ot;
            }
            len = k;
            /*将余数储存起来*/
            if (nut < 10)
                ans.push_back(char(nut + '0'));
            else if (nut >= 10 && nut <= 35)
                ans.push_back(char(nut - 10 + 'A'));
            else if (nut >= 36 && nut <= 61)
                ans.push_back(char(nut - 36 + 'a'));
        }

细节提示
注意0~9转为字符时要加上’0’。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1000;
int nx[N], cx[N];
int main(){
    int t;
    cin >> t;
    int in, ot;
    string num;
    while(t--){
        cin >> in >> ot >> num;
        cout << in << " " << num << endl;
        cout << ot << " ";
        int i = 0, len = num.length();
        for (; i < len; i++){
            if(num[i]-'0'<10)
                nx[i] = num[i] - '0';
            else if(num[i]>='A'&&num[i]<='Z')
                nx[i] = num[i] - 'A' + 10;
            else if(num[i]>='a'&&num[i]<='z')
                nx[i] = num[i] - 'a' + 36;
        }
        int k, val = 1;
        string ans;
        while (val != 0){
            val = 0;
            int nut = 0;
            k = 0;
            nut = 0;
            for (i = 0; i < len;){
                nut = nut * in + nx[i++];
                nx[k++] = nut / ot;
                val += nx[k - 1];
                nut %= ot;
            }
            len = k;
            if (nut < 10)
                ans.push_back(char(nut + '0'));
            else if (nut >= 10 && nut <= 35)
                ans.push_back(char(nut - 10 + 'A'));
            else if (nut >= 36 && nut <= 61)
                ans.push_back(char(nut - 36 + 'a'));
        }
        reverse(ans.begin(), ans.end());
        cout << ans << endl
             << endl;
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值