算法学习专栏——进制转换类型题目

位运算

按位与(&)

计算方式:

有0出0,全1出1

例如

4&5改为二进制

4 –> 0000 0100

5 –> 0000 0101

​ 0000 0100 <–4

因此4&5=4

按位或(|)

计算方式:

有1出1,全0出0

例如

4&5改为二进制

4 –> 0000 0100

5 –> 0000 0101

​ 0000 0101 <–5

因此4|5=5

按位异或(^)

计算方式:

相同为0,不同为1

例如

4&5改为二进制

4 –> 0000 0100

5 –> 0000 0101

​ 0000 0001 <–1

因此4^5=1

用途:交换变量

1
2
3
4
int a = 1, b = 2;
a = a ^ b;
b = a ^ b; // b = a ^ b ^ b = a;
a = a ^ b; // a = a ^ b ^ a;

取反(~)

计算方式:

二进制中的1变0,0变1

位运算符(>> 和 <<)

计算方式:

将一个数的二进制位全部左移(右移)若干位

左移:高位溢出不用,低位补0

右移:低位溢出不用,高位正数补0,负数补1

左移一位相当于乘2,2^n^相当于左移n位,右移同理

例子:

a = 10 = (1010)2

a = a << 2 =(1000)2

一、数的进制转换(—)(简单-)

大家好,我是小刘,现在我正在学习计算机的基础知识:进制转换,但是现在有个问题,我发现学校交给我们进制转换仅仅是2、8、10、16进制之间的转换,现在我想设计一段代码,可以实现任何进制数对任何进制数之间的转换。

注意:字母这里可能为大小写字母,不需要考虑大小写问题,比如Ab23。

输入格式

输入一个字符串 X,X的进制为Y,需要转化为的进制为Z。

输出格式

输出转换为Z进制的数X的格式。

数据范围

$$
1 <= X.length() <= 5\
2<=Y<=36\
2<=Z<=36
$$

输入样例1:

1
2
3
10
2
7

输出样例1:

1
2

输入样例2:

1
2
3
A123
11
7

输出样例2:

1
54142

思路

思路
    可以选择先将这个数转换为10进制,再将其转换为对应进制,这个思路是最常见最简单的一套思路
    

代码

答案(请自己先思考一下再参考)
        
#include < iostream>
#include < algorithm>
#include < vector>
using namespace std;
string x;
int y,z;
int k = 1;
long long ans;
vector C;
int main() 
{
    cin >> x >> y >> z;        
    for (int i = x.size() - 1; i >= 0; i--) 
    {
        if (x[i] >= 'A' && x[i] <= 'Z') ans += (x[i] - 'A' + 10) * k;
        if (x[i] >= 'a' && x[i] <= 'z') ans += (x[i] - 'a' + 10) * k;
        else ans += (x[i] - '0') * k;
        k *= y;
    }
    // 下面这种写法也可以
    //for (int i = x.size() - 1; i >= 0; i--) 
    //{
    //    x[i] = tolower(x[i]); // 这个函数的作用是将字母转换为小写字母,比如'A'变为'a',
    //    if (x[i] >= 'a' && x[i] <= 'z') ans += (x[i] - 'a' + 10) * k;
    //    else ans += (x[i] - '0') * k;
    //    k *= y;
    //}
    while (ans){
        C.push_back(ans % z);
        ans /= z;
    } 
    for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
    return 0;
}
        
    

二、数的进制转换(二)(简单)

编写一个程序,可以实现将一个数字由一个进制转换为另一个进制。

这里有 62 个不同数位 **{0−9,A−Z,a−z}{0−9}**。

输入格式

第一行输入一个整数,代表接下来的行数。

接下来每一行都包含三个数字,首先是输入进制(十进制表示),然后是输出进制(十进制表示),最后是用输入进制表示的输入数字,数字之间用空格隔开。

输入进制和输出进制都在 22 到 6262 的范围之内。

(在十进制下)A=10,B=11,…,Z=35,a=36,b=37,…,z=61 (0−9 仍然表示 0−9)。

输出格式

对于每一组进制转换,程序的输出都由三行构成。

第一行包含两个数字,首先是输入进制(十进制表示),然后是用输入进制表示的输入数字。

第二行包含两个数字,首先是输出进制(十进制表示),然后是用输出进制表示的输入数字。

第三行为空白行。

同一行内数字用空格隔开。

输入样例:

1
2
3
4
5
6
7
8
9
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

输出样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

思路

​ 和上一道题目思路几乎一致

代码

答案(请自己先思考一下再参考)
        #include 
#include < algorithm>
#include < cstring>
using namespace std;
const int Max = 1100;
#define fir(a,b,c) for (int a = b;a <= c;a++)
int t[Max],A[Max],n,m,i,len,k;
char str1[Max], str2[Max];
void solve()
{
    k=0;
    len = strlen(str1);
    for(i=len; i >= 0; i--) 
        t[len - i - 1] = str1[i] -(str1[i]<58 ? 48: str1[i]<97 ? 55: 61);//开始转换成为十进制
    while(len)
    {
    //这个写法大家
        for(i = len; i >= 1; i--) 
        {
            t[i - 1] +=t[i] % m * n;//开始计算,首先*n,为n进制,然后转移到m进制
            t[i] /= m;//当前数已经处理完了
        }
        A[k++] = t[0] % m;//直接加到答案数组中
        t[0] /= m;//当前数已经处理完了
        while(len > 0&& !t[len - 1])  //处理0的情况
            len--;
    }
    str2[k] =NULL;//第k位,我们不需要,直接抛去,利用NULL这个特殊的字符串结束符,具体可以自行百度.
    fir(i,0,k - 1)//这里使用这个写法就是让大家熟悉一下,之后使用这个方法可以简化代码
        str2[k - 1 - i] = A[i]+(A[i] < 10 ? 48: A[i] < 36 ? 55:61);//三目运算符,这段代码的意思是,
        // 找这个数字对应的字母
}
int main()
{
    int t;
    scanf("%d\n",&t);
    while(t--) 
    {
        scanf("%d %d %s\n",&n,&m,str1);
        solve();
        printf("%d %s\n%d %s\n\n",n,str1,m,str2);
    }
    return 0;
}
        
    

三、数列(简单)

给定一个正整数 k,把所有 k 的方幂及所有有限个互不相等的 k 的方幂之和构成一个递增的序列,例如,当 k=3 时,这个序列是:

1,3,4,9,10,12,13,…

该序列实际上就是:3^0^,3^1^,3^0^+3^1^,3^2^,3^0^+3^2^,3^1^+3^2^,3^0^+3^1^+3^2^……

请你求出这个序列的第 N 项的值(N 用 10 进制数表示,从 1 开始)。 

例如,对于 k=3,N=100正确答案应该是 981。

输入格式

输入文件只有 11 行,为 22 个正整数,用一个空格隔开:k,N,。

输出格式

输出文件为计算结果,是一个正整数(在所有的测试数据中,结果均不超过 2.1×1092.1×109)。(整数前不要有空格和其他符号)。

数据范围

$$
3≤k≤15\
10≤N≤1000
$$

输入样例:

1
3 100

输出样例:

1
981

思路

思路
这道题目实质上就是一个扩展思维类型题目,大家可以仔细观察一下题目给出的一串数列,然后再结合二进制来看一下就不难看出就是一个从1~n的二进制数的排列罢了,比如说:对于数字9而言对应二进制位1001,那么我们对应数列的项就是3^0 + 3^3。
    
image-20240212164415749

代码

答案(请自己先思考一下再参考)
        
#include < iostream>
#include < cmath>
using namespace std;
typedef long long LL;
int k, n;
LL ans;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin >> k >> n;
    for (int i = 0; i < 15;i ++) {
        if ((n >> i) & 1) {
            ans += pow(k, i);
        }
    }
    cout << ans;
    return 0;
}