ccpc高职组2021补题
E二进制
这是一个关于二进制的问题。
给定一个正整数x,你需要找到一个最小的正整数y,满足
- x≤y
- y在二进制表示下1的个数为偶数
对于第二个条件,例如:
4的二进制表达是(100)2,不满足。
5的二进制表达是(101)2,满足。
输入格式:
第一行输入一个正整数T(1≤T≤105)代表询问的个数。
对于每组询问,输入一行一个正整数x(1≤x≤109)代表一个询问。
解释:刚开始分析这个二进制数的规律,会发现0~15这16个数字,呈现的规律为YNNYNYYNNYYNYNNY(Y代表1的个数为偶数,N代表奇数),然后进一步分析,16往后16个数的规律与之完全相反,因为相当于在四位二进制数前加了一个1,然后发现这个规律后不难往后推,之后的规律都与这16个有关。本来想用打表的方式,将范围内所有的数判断出来,但是发现范围太大了,所以放弃。
准备暴力一下,因为算了一下10^9折合成2进制一定小于50,所以开了一个数组来存储二进制,判段数组中1的个数是否满足条件,满足就输出原数,否则输出原数+1,但是这时忽略了一个问题就是,原数+1不一定符合条件,再看向我们之前找到的规律,不难发现,如果当前值不符合条件,那么当前值+1或者当前值加2一定会有一个或者都符合条件。所以代码如下:
#include <bits/stdc++.h>
using namespace std;
int pan(long long x){
int a[50]={};
int i=0;
while(x>0)
{
a[i]=x%2;
x/=2;
//cout<<a[i]<<endl;
i++;
}
//for(int j=0;j<50;j++)cout<<a[j]<<" ";
//cout<<endl;
int cnt=0;
for(int j=0;j<i;j++){
if(a[j]==1)
cnt++;
}
if(cnt%2==0)
return 1;
else
return 0;
}
int main(){
long long n;
int t;
cin>>t;
while(t--){
cin>>n;
if(pan(n))
cout<<n<<endl;
else if(pan(n+1))
cout<<n+1<<endl;
else if (pan(n+2))
cout<<n+2<<endl;
}
return 0;
}
基于这个思路可以用位运算进行简化代码。
#include <bits/stdc++.h>
using namespace std;
int pan(long long x){
int cnt=0;
while(x>0){
cnt++;
x&=(x-1);
}
if(cnt%2==0)
return 1;
else
return 0;
}
int main(){
long long n;
int t;
cin>>t;
while(t--){
cin>>n;
if(pan(n))
cout<<n<<endl;
else if(pan(n+1))
cout<<n+1<<endl;
else if (pan(n+2))
cout<<n+2<<endl;
}
return 0;
}