当前位置:首页 > GESP > 洛谷B3870题:位操作与二进制转换解决变长编码

洛谷B3870题:位操作与二进制转换解决变长编码

6个月前 (08-28)

洛谷B3870题:位操作与二进制转换解决变长编码 洛谷题解 进制转换 位运算 C++ GESP GESP四级 第1张

一、题目解读

洛谷B3870题要求将给定的无符号长整型数转换为可变长度的字节编码,并输出其十六进制表示。题目核心在于设计一种高效的编码方案,需处理数字的二进制位分组、最高位标记及字节顺序反转等细节。该问题考察对二进制位操作的理解与算法逻辑的严谨性,尤其在边界条件(如0的特殊编码)与分组补位机制上的实现。

二、解题思路

1. 二进制转换与去前导0:自定义toBinaryString函数将数字转为二进制串,通过倒序取余法生成,并去除前导0(避免无效位)。

2. 分组与最高位标记:将二进制串按7位分组,不足位补0。通过makeByte函数生成字节,非最后一组设置最高位为1,区分数据段与结束标志。

3. 字节反转输出:因处理从低位开始,最终需反转字节顺序,确保正确解码顺序。

4. 边界处理:0的特殊情况单独编码为单字节0,避免空输出。

三、解题步骤

1. 输入数字N:通过cin获取用户输入的无符号长整型数。

2. 二进制转换:调用toBinaryString(N)生成二进制串,去除前导0。

3. 分组编码:

○ 从末尾开始,每次取最长7位子串(不足补0)。

○ 通过makeByte将子串转为字节,根据位置标记最高位。

○ 存入bytes容器,记录编码结果。

4. 字节反转:使用reverse函数反转字节顺序,确保高位在前。

5. 输出十六进制:循环遍历字节,按格式%02X输出,空格分隔。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 将数字转换为二进制字符串(去除前导0)
string toBinaryString(unsigned long long n) {
    if (n == 0) return "0"; // 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; // 不足位补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编码为单字节0
        return bytes;
    }
    
    string binary = toBinaryString(n);
    int len = binary.length();
    int pos = len;
    
    while (pos > 0) {
        int start = max(0, pos - 7); // 从末尾开始取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;
}

五、总结

该解法通过模块化函数(二进制转换、字节生成、主逻辑)实现清晰编码流程,兼顾效率与边界处理。核心技巧在于:

● 二进制倒序生成避免额外反转操作;

● 分组补位与最高位标记简化解码逻辑;

● 字节反转确保大端序输出。

适用于需处理变长二进制数据的场景,算法简洁且易于扩展。未来可探索更紧凑的位运算优化,或结合动态规划优化分组效率。


原创内容 转载请注明出处

分享给朋友:

相关文章

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

牛客14496题解:括号最大深度问题(栈思想与代码优化)

牛客14496题解:括号最大深度问题(栈思想与代码优化)

一、题目解读牛客14496题要求计算给定括号字符串中的最大深度。例如,对于字符串 "(()())",最大深度为2。题目考察对括号嵌套结构的理解,以及如何通过编程找到最深嵌套层次。二...

2024年GESP四级宝箱题(洛谷P4006)题解:滑动窗口算法优化最长子序列和

2024年GESP四级宝箱题(洛谷P4006)题解:滑动窗口算法优化最长子序列和

一、题目解读本题为2024年GESP四级中的“宝箱”问题(对应洛谷P4006),要求在一个由n个宝箱组成的序列中,找出一个连续子序列,使得该子序列中宝箱价值之和最大,且子序列中最大值与最小值的差不超过...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

洛谷1220题解:动态规划与区间DP优化解法(附代码注释)

一、题目解读洛谷1220题要求计算在n个位置放置灯的情况下,通过关闭连续区间灯并移动至区间端点,使得总耗电量最小。需考虑灯的功率与位置差异,设计高效的算法求解最优策略。二、解题思路1. 动态规划 +...

牛客NC67题解:汉诺塔递归算法与解题步骤

牛客NC67题解:汉诺塔递归算法与解题步骤

一、题目解读牛客NC67题要求解决汉诺塔问题,这是一个经典的递归算法题目。题目给定整数n,代表汉诺塔中的盘子数量,需要输出将n个盘子从起始柱移动到目标柱的所有步骤。汉诺塔问题规则为:每次只能移动一个盘...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。