题目大意:
已知有n瓶水,每瓶水有1升,我们可以把相同容量的两瓶水合成一瓶水。同时我们可以买无数瓶1升水
问假若我们需要只剩下k瓶水,我们最少需要买多少瓶水。
解题思路:
这题有一个核心的结论:当我们把n转为二进制来观看时,二进制中1的个数即为n瓶最后可以到达的瓶数。我们举个例子:若n=8
bin(8) = 1000,
8=4+4
4=2+2
2=1+1
上面的数字代表升数,我们发现2的n次幂都是可以最终倒为1杯水。
所以,当k<=countbit(n)时,我们一瓶水都不用买。其中countbit(n)表示n的二进制表示中有多少个1。
那么,我们需要买多少瓶水呢? 比如我们现在有a个1,那么我们需要减少a-k个1,所以我们可以对n的二进制从右向左扫描,a-k+1个1,得到这个数字的位置后,我们再向左扫描到第一个0,那个就是我们需要置1的地方pos2,然后我们只需要用pow(2,pos2)减去pos2这个数字后面的原来n表示的二进制数,例如:n= 10 1101,pos2指向从左往右的第二个零,那么我们需要用pos(2,pos2) 减去后面的1101即得出答案
废话:这题非常巧妙的考了一个数字的二进制表示,所以数论题有时候我们需要从二进制的角度去观察。
#include <bits/stdc++.h>
#define ing long long
using namespace std;
queue<int> q;
int countbit(int in){
int ans=0;
while(in){
if(in&1){ans++;
q.push(1);
}else q.push(0);
in>>=1;
}
q.push(0);
return ans;
}
int32_t main(){
int n,k;cin>>n>>k;
if(k>=n){
cout<<k-n<<endl;
return 0;
}
int bitno=countbit(n);
if(bitno<=k){
cout<<0<<endl;
return 0;
}
int ones=bitno-k+1;
int count=0;
int tmpno=0;
while(ones!=0){
int no=q.front();q.pop();
if(no==1){ones-=1;
tmpno+=pow(2,count);
}
count++;
}
int nowe;
while(1){
int no=q.front();q.pop();
if(no==1){
tmpno+=pow(2,count);
}
if(!no){
nowe=pow(2,count);
cout<<nowe-tmpno<<endl;
return 0;
}
count++;
}
return 0;
}