【题解】倒水
题目描述
一天,树树买了N个容量可以认为是无限大的瓶子,初始时每个瓶子里有1升水。树树发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子合并,把一个瓶子里的水全部倒进另一个瓶子,然后把空瓶丢弃(不能丢弃有水的瓶子)。
显然在某些情况下树树无法达到目标,比如N=3,K=1。此时树树会重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以达到目标。
现在树树想知道,最少需要买多少新瓶子才能达到目标呢?
输入输出格式
输入格式:
一行,两个正整数N,K(1≤N≤\(10^9\),K≤1000)。
输出格式:
一个非负整数,表示最少需要买多少新瓶子。
输入输出样例
输入样例一:
3 1
输出样例一:
1
输入样例二:
13 2
输出样例二:
3
输入样例三:
1000000 5
输出样例三:
15808
说明
样例说明:
考虑lowbit运算。所谓lowbit运算,就是把n的二进制的高位1全部清空,只留下最低位的1,比如10的二进制是1010,则lowbit(n)=lowbit(1010)=0010(二进制)。
数据规模:
对于30%的数据,N≤3×\(10^5\);
对于50%的数据,n≤\(10^7\);
对于100%的数据,如题目所述。
因为题目提示了lowbit运算,所以就是要用位运算
而做位运算的基本思路就是
通过特殊到一般,找出规律
我们来推算一下样例
输入:
3 1
推算:
1 1 1
2 1
把能合并的全部合并后,发现剩下2个,然后把(3)10转换为二进制得到(11)2
也就是说,合并之后所剩下的瓶子个数,就是原数n的二进制中1的个数
那么,到底要买多少个瓶子呢?
题目提示我们考虑lowbit运算
(3)10=(11)2
3+lowbit(3)=(11)2+(1)2=(100)2
也就是说,每加上一个lowbit(n),就会把最低位的1往高位移动,然后就能合并,消除
就是当剩下瓶子数大于K时,就往n中加lowbit(n)
AC代码:
#include<iostream>
using namespace std;
int n,k;
int lowbit(int n)
{
return n&(-n);
}
int cnt(int n)
{
int res;
while(n!=0)
{
res+=n%2;
n/=2;
}
return res;
}
int main()
{
cin>>n>>k;
int ans=0;
while(cnt(n)>k)
{
ans+=lowbit(n);
n+=lowbit(n);
}
cout<<ans;
}
注意
lowbit(n)=n&(-n)
有可能要用long long