202603-1 二进制回文串
题目描述
对于一个正整数 nnn,我们将其转换为不含前导零的二进制表示,如果这个二进制序列从左向右读与从右向左读完全相同,则称该数为二进制回文数。例如,999 的二进制表示为 (1001)2(1001)_2(1001)2,是二进制回文数;121212 的二进制表示为 (1100)2(1100)_2(1100)2,不是二进制回文数。
你的任务是:给定一个正整数 nnn,计算在 111 到 nnn 的范围内二进制回文数的数量。
输入格式
输入一行,包含一个正整数 nnn。
输出格式
输出一行,包含一个数,表示在 111 到 nnn 的范围内二进制回文数的数量。
样例输入 1
15
样例输出 1
6
提示
【样例解释】
样例 1 中,111 到 151515 范围内 111、333、555、777、999、151515 是二进制回文数。
【数据范围】
1≤n≤1051 \leq n \leq 10^51≤n≤105
解题思路
方法:数位翻转比较法
直接遍历 111 到 nnn 的每个数,将其二进制表示从低位到高位依次取出并重新组合成一个新的数 mmm,如果 mmm 与原数相等,则说明该数的二进制表示是回文的。
核心思想:
- 将原数的二进制位从低到高依次取出(j%2j\%2j%2)
- 同时将取出的位按从左到右的顺序重新组合(m=m∗2+j%2m = m*2 + j\%2m=m∗2+j%2)
- 最终 mmm 就是原数二进制表示的翻转,若 m==im==im==i,则为回文数
代码解析
cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, cnt = 0;
cin >> n;
// 遍历1到n的所有数
for (int i = 1; i <= n; i++) {
int j = i, m = 0;
// 将i的二进制位从低到高取出,同时构建翻转后的数m
while (j) {
m = m * 2 + j % 2; // 取出最低位,添加到m的最高位
j /= 2; // 移除最低位
}
// 如果翻转后的数等于原数,说明是二进制回文数
if (m == i) cnt++;
}
cout << cnt;
return 0;
}
样例验证
| 数字 | 二进制表示 | 翻转后的值 | 是否回文 |
|---|---|---|---|
| 1 | 1 | 1 | ✓ |
| 2 | 10 | 01=1 | ✗ |
| 3 | 11 | 11 | ✓ |
| 4 | 100 | 001=1 | ✗ |
| 5 | 101 | 101 | ✓ |
| 6 | 110 | 011=3 | ✗ |
| 7 | 111 | 111 | ✓ |
| 8 | 1000 | 0001=1 | ✗ |
| 9 | 1001 | 1001 | ✓ |
| 10 | 1010 | 0101=5 | ✗ |
| 11 | 1011 | 1101=13 | ✗ |
| 12 | 1100 | 0011=3 | ✗ |
| 13 | 1101 | 1011=11 | ✗ |
| 14 | 1110 | 0111=7 | ✗ |
| 15 | 1111 | 1111 | ✓ |
结果:共6个二进制回文数(1、3、5、7、9、15)