题目描述
给定一个正整数N,求出一个正整数M,M大于N,且二进制下M与N的“1”的个数相同,在所有满足条件的M中,将最小的一个输出
输入
第一行输入为整数T(T<60),表示T组测试数据
每组测试数据输入一个正整数N,N<=1e9
输出
每组测试数据输出一个正整数M,且是所有满足条件中最小的一个
样例输入
3
7
23
14232
样例输出
11
27
14241
解析
题意:给出一个正整数N,求出二进制1个数与N相同的最小的正整数M。
- 首先计算N的二进制,为了方便运算,在最高位补一个0。
- 比如数字11补0的二进制为01011,要想找到比他小的数,首先找到最低位的1,这里表示如下01011。
- 然后找到这个1前面最近的0,即01011,把他们交换后为01110。
- 注意01110并不是最小的M,此时需要把1后面所有的1放到最低位,即01101,十进制为13,就是所满足的数。
代码
实现起来的代码未精简,有些重复判断,读者可自行修改。
#include <iostream>
#include <cstring>
using namespace std;
void solve(long long k){
if(k==1){
printf("%lld\n",k<<1);
return;
}
long long def=k;
string s="";
while(k>0){
s+=(char(k&1)+'0');
k=k>>1;
}
s+='0';
int min0=-1,min1=-1;
for(int i=0;i<s.size();i++){
if(min1==-1&&s[i]=='1') min1=i;
if(min1!=-1&&s[i]=='0'){
min0=i;break;
}
}//找到最小的1和他前面最小的0
if(min1==s.size()-1){
printf("%lld\n",def<<1);
return;
}
s[min0]='1';
s[min1]='0';
int ones=0;
for(int i=0;i<min0;i++){
if(s[i]=='1') ones++;
s[i]='0';
}
for(int i=0;i<ones;i++) s[i]='1';
long long out=0;
for(int i=s.size()-1;i>=0;i--){
out=out<<1;
out+=s[i]-'0';
}
printf("%lld\n",out);
}
int main(){
int n;
scanf("%d",&n);
while(n--){
long long k;
scanf("%lld",&k);
solve(k);
}
return 0;
}