题解:洛谷 B4499 二进制回文串

【题目来源】

洛谷:B4499 [GESP202603 三级] 二进制回文串 - 洛谷

【题目描述】

对于一个正整数 \(n\),我们将其转换为不含前导零的二进制表示,如果这个二进制序列从左向右读与从右向左读完全相同,则称该数为二进制回文数。例如,\(9\) 的二进制表示为 \((1001)_2\),是二进制回文数;\(12\) 的二进制表示为 \((1100)_2\),不是二进制回文数。

你的任务是:给定一个正整数 \(n\),计算在 \(1\)\(n\) 的范围内二进制回文数的数量。

【输入】

输入一行,包含一个正整数 \(n\)

【输出】

输出一行,包含一个数,表示在 \(1\)\(n\) 的范围内二进制回文数的数量。

【输入样例】

15

【输出样例】

6

【核心思想】

  1. 问题分析:给定正整数 \(n\),需要统计 \([1, n]\) 范围内二进制回文数的个数。二进制回文数是指其二进制表示(不含前导零)从左到右读与从右到左读完全相同的数。例如 \(9 = (1001)_2\) 是回文数,\(12 = (1100)_2\) 不是。本质是进制转换 + 回文判定的组合问题。

  2. 算法选择

    • 进制转换:将十进制数转换为二进制字符串表示
    • 回文判定:将字符串与其反转后的字符串比较,相同则为回文
  3. 关键步骤

    • 进制转换函数 Dtom(n, m)
      • 初始化空字符串 \(ans\)
      • \(n > 0\) 时循环:
        • \(ans \leftarrow d[n \bmod m] + ans\)(将新位插入字符串前端)
        • \(n \leftarrow \lfloor n / m \rfloor\)
      • 返回 \(ans\)
    • 主流程
      • 读入 \(n\)
      • 遍历 \(i\)\(1\)\(n\)
        • \(t \leftarrow\) Dtom(i, 2)(转换为二进制字符串)
        • \(s \leftarrow t\)(保存原串)
        • reverse(t.begin(), t.end())(反转字符串)
        • \(t = s\),则 cnt++
      • 输出 \(cnt\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \cdot \log n)\),每个数转换二进制 \(O(\log i)\),反转和比较 \(O(\log i)\)
    • 空间复杂度:\(O(\log n)\),存储单个数的二进制字符串
  5. 进制转换与回文判定的核心思想

    • 短除法进制转换:通过反复取模和整除,从低位到高位提取 \(m\) 进制下的各位数字,利用字符串前插(d[n % m] + ans)保证高位在前,得到标准进制表示
    • 回文对称性:回文串的正读反读相同,因此将字符串反转后与原串比较即可判定,无需逐位双指针扫描
    • 前导零自然消除:短除法转换过程中,当 \(n\) 变为 \(0\) 时停止,最高位不会为 \(0\),天然满足"不含前导零"的要求
    • 通用进制框架Dtom 函数通过字符集 d 支持最多 \(16\) 进制,本题传入 \(m = 2\) 即得二进制,体现了算法的可复用性
    • 适用于进制转换、回文数统计、数字模式识别等基础数论与字符串结合问题

【算法标签】

入门 #语法基础

【代码详解】

#include <bits/stdc++.h>  // 包含所有标准库头文件
using namespace std;       // 使用标准命名空间

int n, cnt;  // 定义全局变量:n(输入的数),cnt(计数器,记录符合条件的数的个数)

// 将十进制数n转换为m进制表示的字符串
string Dtom(int n, int m)
{
    // 定义字符集,支持最多16进制(0-9, A-F)
    string d = "0123456789ABCDEF";

    string ans = "";  // 初始化结果字符串为空

    // 将十进制数n转换为m进制
    while (n > 0)
    {
        // 获取n除以m的余数,即当前位的值
        // 余数作为索引在d中查找对应的字符
        // 注意:这里将新得到的位添加到字符串的前面
        ans = d[n % m] + ans;

        // n除以m,为处理下一位做准备
        n /= m;
    }

    return ans;  // 返回转换后的m进制字符串
}

int main()  // 主函数入口
{
    cin >> n;  // 输入整数n

    // 遍历1到n的所有整数
    for (int i = 1; i <= n; i++)
    {
        // 将整数i转换为二进制字符串
        string t = Dtom(i, 2);

        // 保存原始字符串
        string s = t;

        // 将字符串t反转
        reverse(t.begin(), t.end());

        // 判断反转后的字符串是否与原字符串相同
        // 即判断二进制表示是否是回文数
        if (t == s)
        {
            cnt++;  // 如果是回文数,计数器加1
        }
    }

    cout << cnt << endl;  // 输出满足条件的数的个数

    return 0;  // 程序正常结束
}

【运行结果】

15
6
posted @ 2026-07-01 19:09  团爸讲算法  阅读(24)  评论(0)    收藏  举报