题目描述
最近,蒟蒻小明的班上准备拍一次特殊的集体照,因为队形要求是要班上的所有32
名同学全部站成一排。而好学的小明发现,在这种情况下,如果将男女生分别看成1
和0
,照相的队形就能组成一个32位
长的二进制数,而二进制又能转化成十进制,因此一个不同的队形就对应了一个不同的数字。
小明想考一考他的同桌,就想出了一个问题:给定原始队形x
,问如何重新排列队伍,才能得到第一个在数值上比原始队形大的数y
呢。但其实身为蒟蒻的小明自己也不知道答案,所以就把计算答案这个任务委托给了聪明的你,请你写一个程序帮帮孩子。
提示:
y 是大于x的最小整数。比如对于x=13,表示原本的队形为0⋯01101
,则对应的y
应为14
,表示新队形为0⋯01110
。
输入格式
输入包含若干行,每行一个整数x,表示原本的队伍组合成的数值大小,以x=0
表示输入结束。
输出格式
每行一个整数,表示每个x
对应的y
。
样例
输入数据 1
1
2
3
4
5
0
输出数据 1
2
4
5
8
6
数据范围
1≤x≤232−1
代码示例
#include<bits/stdc++.h>
using namespace std;
int main(){
int x;
while(cin>>x&&x){
int y = 0;
int t = 0;
int n = 0;
while(t=x&-x,x-=t,x&t<<1)y|=1<<n++;
printf("%d\n",y|t<<1|x);
}
return 0;
}
代码的执行流程如下:
循环读入:通过 while 循环读入整数 x,只要 x 不为0,就继续处理。
初始化变量:
int y = 0; 初始化结果变量 y。
int t = 0; 初始化用来表示 x 的最低位的1的权值。
int n = 0; 初始化用来记录 x 的末尾0的数量。
找到最低位的1并处理:
while(t=x&-x,x-=t,x&t<<1) 的循环做了几件事:
t = x & -x; 找到 x 的最低位的1的权值。
x -= t; 从 x 中移除这个1。
x & t << 1; 检查在移除的1的左侧是否有1(即检查是否是连续的1)。
如果左侧有1,说明在这个位置上进行翻转会得到一个更大的数。
y |= 1 << n++; 如果有连续的1,则在结果 y 中对应的位置上放置1。
构造结果:
printf(“%d\n”,y|t<<1|x); 输出结果。这里 y | t << 1 | x 通过以下步骤构造下一个更大的数:
y:是原始 x 末尾0的数量对应的二进制数。
t << 1:是将 x 的最低位的1左移一位后得到的数。
x:是除了最低位的1之外, x 的剩余部分。
结束条件:
当输入的 x 为0时,结束循环。
代码执行流程如下:
-
循环读入:通过 while 循环读入整数 x,只要 x 不为 0,就继续处理。
-
初始化变量:
int y = 0;
初始化结果变量 y。int t = 0;
初始化用来表示 x 的最低位的 1 的权值。int n = 0;
初始化用来记录 x 的末尾 0 的数量。
-
找到最低位的 1 并处理:
while(t = x & -x, x -= t, x & t << 1)
的循环做了几件事:t = x & -x;
找到 x 的最低位的 1 的权值。x -= t;
从 x 中移除这个 1。x & t << 1;
检查在移除的 1 的左侧是否有 1(即检查是否是连续的 1)。- 如果左侧有 1,说明在这个位置上进行翻转会得到一个更大的数。
y |= 1 << n++;
如果有连续的 1,则在结果 y 中对应的位置上放置 1。
-
构造结果:
printf("%d\n", y | t << 1 | x);
输出结果。这里y | t << 1 | x
通过以下步骤构造下一个更大的数:y
:是原始 x 末尾 0 的数量对应的二进制数。t << 1
:是将 x 的最低位的 1 左移一位后得到的数。x
:是除了最低位的 1 之外, x 的剩余部分。
-
结束条件:
- 当输入的 x 为0时,结束循环。