洛谷B3870题(2023年GESP四级):如何用C++实现数字的变长编码?

一、题目解读
B3870题要求将任意非负整数转换为特定字节编码格式,其核心考察点包括:
二、解题思路
解决方案采用以下关键技术:
分层处理架构:先转换二进制,再分组处理,最后字节编码
动态补位机制:通过substr和while循环确保7位分组完整性
双端队列思想:正向分组但反向存储,通过reverse实现顺序校正
位运算优化:采用位或(|)和位移(<<)操作提升编码效率
三、实现步骤
二进制转换阶段:
处理n=0特殊情况
通过除2取余法获取二进制字符串
使用reverse校正位序
7位分组阶段:
从低位向高位截取子串
动态补0确保每组7位
标记是否为末组(pos==0)
字节编码阶段:
通过makeByte函数设置最高位标记
末组最高位保持0,非末组设为1
输出处理阶段:
反转字节顺序满足题目要求
用printf格式化输出十六进制
四、完整代码实现(含注释)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 将数字转换为二进制字符串(去除前导0)
string toBinaryString(unsigned long long n) {
if (n == 0) return "0";
string binary;
while (n > 0) {
binary += (n % 2) + '0';
n /= 2;
}
reverse(binary.begin(), binary.end());
return binary;
}
// 将7位二进制字符串转换为字节(添加最高位)
char makeByte(const string& bits, bool isLast) {
char byte = 0;
for (int i = 0; i < 7; ++i) {
char bit = (i < bits.size()) ? bits[i] - '0' : 0;
byte |= bit << (6 - i);
}
if (!isLast) byte |= 1 << 7; // 设置最高位为1(如果不是最后一组)
return byte;
}
// 主处理函数
vector<char> encodeNumber(unsigned long long n) {
vector<char> bytes;
if (n == 0) {
bytes.push_back(0); // 特殊情况:0的编码是00000000
return bytes;
}
string binary = toBinaryString(n);
int len = binary.length();
int pos = len;
while (pos > 0) {
int start = max(0, pos - 7);
string group = binary.substr(start, pos - start);
pos = start;
// 补足7位
while (group.length() < 7) {
group = "0" + group;
}
bool isLast = (pos == 0);
bytes.push_back(makeByte(group, isLast));
}
// 反转字节顺序(因为是从低位开始处理的)
reverse(bytes.begin(), bytes.end());
return bytes;
}
int main() {
unsigned long long N;
cin >> N;
vector<char> encoded = encodeNumber(N);
// 输出十六进制表示
for (size_t i = encoded.size(); i >0; i--) {
if (i != encoded.size()) cout << " ";
printf("%02X", (unsigned char)encoded[i-1]);
}
cout << endl;
return 0;
}五、算法总结
该解决方案展现了三个典型工程实践:
防御性编程:对n=0的特殊处理
位操作技巧:makeByte中的位运算组合
数据封装思想:encodeNumber函数的模块化设计 其时间复杂度为O(log n),空间复杂度O(⌈log n/7⌉),适合处理大整数场景。
原创内容 转载请注明出处
