蓝桥杯基础--进制转换

目录

[1. 进制的本质](#1. 进制的本质)

[2. 任意进制转换为十进制](#2. 任意进制转换为十进制)

[3. 十进制转换为任意进制](#3. 十进制转换为任意进制)

[4. 例题](#4. 例题)

4.1进制

4.2九进制转十进制

4.3进制转换


在蓝桥杯以及各种编程竞赛中,进制转换是一个非常经典且高频考察的基础知识点。无论是单独作为一道填空题出现,还是作为复杂大题中的一个小步骤,熟练掌握进制转换的底层逻辑和代码模板,都是拿到高分的重要保障。

今天,我们就来拨开进制的迷雾,彻底搞懂进制转换的核心方法,并结合三道蓝桥杯真题进行实战演练。

1. 进制的本质

什么是进制?通俗地讲,进制就是一种计数的规则。我们平时在生活中最常用的是"十进制",它的核心规则就是"逢十进一"。每一位上的数字只能是 0 到 9,当某一位加到 10 的时候,就要向前一位进 1。

同理,"二进制"就是逢二进一(数字只有 0 和 1),"十六进制"就是逢十六进一(数字除了 0 到 9,还引入了 A 到 F 来表示 10 到 15)。

进制的另一个核心概念是"位权"。以十进制数字 345 为例,它其实代表的是 3 乘以 100,加上 4 乘以 10,再加上 5 乘以 1。这里面的 100、10、1,就是各个位置上的"权重"。任何进制的本质,都可以看作是各个位上的数字乘以对应位置的权重,然后全部相加。

2. 任意进制转换为十进制

掌握了进制的本质,我们就很容易理解如何把一个任意的 k 进制数转换成十进制了。

最直接的方法是从左到右(从高位到低位)遍历这个数的每一位,每次都把当前累积的结果乘以 k,再加上当前位上的数字。这种方法在算法中类似于"秦九韶算法",它的好处是不需要去计算权重的多少次方,只需要用一个循环就能轻松搞定。

核心代码模板片段:

复制代码
ll x = 0;
for(int i = 1; i <= n; i++)
{
    x = x * k + a[i];
}
cout << x << '\n';

3. 十进制转换为任意进制

把十进制转换为任意的 k 进制,我们通常使用"除 k 取余法"。

具体操作是:把十进制数不断地除以 k,每次除法得到的"余数"就是目标 k 进制数的对应位上的数字。我们一直除,直到原来的数字变成 0 为止。

需要特别注意的是,我们最先求出来的余数,实际上是 k 进制数的最末尾(也就是最低位)。所以当我们把所有余数依次存入数组或字符串后,还需要将其整体"翻转"一下,才能得到正确的、高位在前的结果。

核心代码模板片段:

复制代码
ll x;
cin >> x;
while(x) a[++cnt] = x % k, x /= k;
reverse(a + 1, a + 1 + cnt); // 翻转,使高位在1的位置

4. 例题

下面我们结合三道蓝桥杯真题,来看看这两套模板在实战中是如何应用的。

4.1进制

https://www.lanqiao.cn/problems/2489/learning/?page=1&first_category_id=1&name=%E8%BF%9B%E5%88%B6

思路解析: 这是一道纯粹的十六进制转十进制的填空题。给定的十六进制字符串是 "2021ABCD"。 我们可以完全套用"任意进制转十进制"的模板。首先把字符串里的字符转换成对应的数字存入数组,注意 A 到 F 需要特殊处理转换为 10 到 15。然后再做累乘求和。

复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 50;
int a[N];

int main()
{
  string s = "2021ABCD";
  for(int i = 0; i < s.length(); i++)
  {
    if('0' <= s[i] && s[i] <= '9') a[i + 1] = s[i] - '0';
    else a[i + 1] = s[i] - 'A' + 10;
  }

  ll x = 0;
  for(int i = 1; i <= s.length(); i++)
  {
    x = x * 16 + a[i];
  }
  cout << x << '\n';
  return 0;
}

第二种极简解法代码: 因为十六进制是非常常用的计算机底层进制,C++ 语言本身就原生支持直接读取和输出。只要在数字前面加上 0x 前缀,编译器就会自动把它当成十六进制,并在输出时默认转成十进制打印。

复制代码
#include <bits/stdc++.h>
using namespace std;

int main()
{
  unsigned int x = 0x2021ABCD;
  cout << x << '\n';
  return 0;
}

4.2九进制转十进制

https://www.lanqiao.cn/problems/2095/learning/?page=1&first_category_id=1&problem_id=2095

思路解析: 这题是把九进制的 "2022" 转成十进制。和上一题思路一模一样,只是把乘数 16 换成了 9。因为只有数字没有字母,转换起来更方便。

第一种数组写法代码:

复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 10;
int a[N];
int main()
{
  string s = "2022";
  for(int i = 1; i <= s.length(); i++)
  {
    a[i] = s[i - 1] - '0';
  }
  ll x = 0;
  for(int i = 1; i <= s.length(); i++)
  {
    x = x * 9 + a[i];
  }
  cout << x << '\n';
  return 0;
}

第二种精简循环写法代码: 为了让代码更优雅,我们甚至不需要借助额外的数组,直接在遍历字符串字符的同时,一边转换数字一边累加。

复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main()
{
  ll x = 0;
  string s = "2022";
  for(char c : s)
  {
    x = x * 9 + (c - '0');
  }
  cout << x << '\n';
  return 0;
}

4.3进制转换

https://www.lanqiao.cn/problems/1230/learning/?page=1&first_category_id=1&problem_id=1230

思路解析: 这是一道非常综合的进制转换题,要求把一个 N 进制的字符串转换为 M 进制的字符串输出。 解题核心思路是把"十进制"作为一座桥梁:先用模板 1 把 N 进制字符串转成十进制整数,然后再用模板 2 把这个十进制整数转换为 M 进制的字符串。 在代码实现上,我们把大任务拆分成了几个功能单一的小函数,这样逻辑非常清晰,也不容易出错。

参考代码:

复制代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// 字符转数字
inline int char2num(char c)
{
  if(isdigit(c)) return c - '0';
  return c - 'A' + 10;
}

// 数字转字符
inline char num2char(int x)
{
  if(x < 10) return x + '0';
  return x - 10 + 'A';
}

// N进制字符串 -> 十进制整数
ll str2dec(const string &s, int n)
{
  ll num = 0;
  for(char c : s)
  {
    num = num * n + char2num(c);
  }
  return num;
}

// 十进制整数 -> M进制字符串
string dec2str(ll num, int m)
{
  if(num == 0) return "0";
  string res;
  while(num)
  {
    res += num2char(num % m);
    num /= m;
  }
  reverse(res.begin(), res.end());
  return res;
}

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int T;
  cin >> T;
  while(T--)
  {
    int N, M;
    string s;
    cin >> N >> M >> s;
    ll dec = str2dec(s, N);
    cout << dec2str(dec, M) << '\n';
  }
  return 0;
}

本章完。

相关推荐
雪域迷影2 小时前
OpenHarmony 电源管理模块状态转换分析
c++·openharmony·电源管理部件
xjdkxnhcoskxbco2 小时前
Kotlin Lambda 变量捕获
android·开发语言
沐知全栈开发2 小时前
ASP TextStream
开发语言
Yu_Lijing2 小时前
基于C++的《Head First设计模式》笔记——解释器模式
c++·设计模式·解释器模式
人间打气筒(Ada)2 小时前
go实战案例:如何在 Go-kit 和 Service Meh 中进行服务注册与发现?
开发语言·后端·golang·istio·go-kit
Blasit2 小时前
Qt 程序打包,运行提示找不到或无法加载平台插件 qwindows.dll
开发语言·windows·qt
C++ 老炮儿的技术栈2 小时前
c++常见配置文件格式 JSON、INI、XML、YAML 它们如何解析
xml·开发语言·c++·windows·qt·json
Elieal2 小时前
java基础面试
java·开发语言·面试
阿Y加油吧2 小时前
力扣链表高频题:两两交换节点 + K个一组翻转链表(保姆级思路+满分代码)
算法·leetcode·链表