【题解】倒水

题目描述

一天,树树买了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

posted @ 2020-05-21 12:51  X_OR  阅读(366)  评论(0编辑  收藏  举报