蓝桥杯基础--进制转换

目录

[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;
}

本章完。

相关推荐
Elastic 中国社区官方博客1 分钟前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn18814 分钟前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn1 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su1 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
传奇开心果编程1 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用
residual_fan2 小时前
船用柴油机动态机动工况故障诊断:控制感知仿射网络(CAAN)的技术实现
人工智能·算法·数据挖掘·数据分析
qetfw2 小时前
Bash 变量:export、位置参数与默认值展开验证
linux·开发语言·chrome·bash
电子云与长程纠缠2 小时前
UE5魂系游戏开发教程05
开发语言·学习·游戏·ui·ue5
syagain_zsx2 小时前
BRpc 二次封装:Channel 管理、服务管理与回调工厂
c++·学习·程序人生·rpc·谷歌
其实防守也摸鱼2 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全