题目
E - Envious Exponents
题意:给出N,K,求M;M为大于N的可以写成k个2的几次幂的最小值。
思路:想到二进制,为2的幂次方的和,先将N转换成二进制,记录1的个数ans,分为一下三种情况;
第一:若 ans>k,从低位的1位补0,直到ans=k时,转换成第二种情况;
第二:若 ans=k,从最低位开始从后向前找,首次出现1的位置,再向前找首次出现0的位置cnt,将cnt的值变为1,cnt之前的值全部清0。再从最低位开始补1,直到ans=k。(cnt即为非前置0的位置)
第三:若 ans<k,从低位非0位补1,直到ans=k。(从最低位补1,所以是最小的M)。
再将转换后的二进制转换成十进制,注意题目数据的范围,使用long long。
AC代码
#include <bits/stdc++.h>
using namespace std;
int q[100];
int main()
{
long long N,M;
int k;
int top=0,ans=0;
cin>>N>>k;
M=N;
while(M!=0)
{
q[++top]=M%2;
if(M%2==1)
ans++;
M/=2;
}
if(ans>k)//需要1的个数小于本来的,转换成相同的
{
for(int i=1; i<=top; i++)
{
if(q[i]==1)
{
q[i]=0;
ans--;
}
if(ans==k)
break;
}
}
int cnt=0;
int flag=0;
if(ans==k)//需要1的个数等于本来的
{
for(int i=1; i<=100; i++)
{
if(q[i]==1)
{
flag=1;
}
if(q[i]==0&&flag==1)
{
cnt=i;//找到非前置0;
q[i]=1;
ans++;
break;
}
}
for(int i=cnt-1;i>=1;i--)
{
if(q[i]==1)
{
q[i]=0;
ans--;
}
}
for(int i=1;i<=cnt;i++)
{
if(ans==k)
break;
else if(ans<k)
{
q[i]=1;
ans++;
}
}
}
if(ans<k)//需要1的个数大于本来的
{
for(int i=1;;i++)
{
if(q[i]==0)
{
q[i]=1;
ans++;
}
if(ans==k)
break;
}
}
long long sum=0;
long long x=1;
for(int i=1; i<=100; i++)
{
if(q[i]==1)
{
sum=sum+x;
}
x=x*2;
}
cout<<sum<<endl;
return 0;
}