• 【题解】倒水


    题目描述

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

  • 相关阅读:
    梦的解析 —— 梦知道答案
    梦的解析 —— 梦知道答案
    数学骗术
    数学骗术
    vs 外部依赖项、附加依赖项以及如何添加依赖项目
    vs 外部依赖项、附加依赖项以及如何添加依赖项目
    二叉搜索树相关性质的应用
    Haskell 差点儿无痛苦上手指南
    Android下用Properties保存程序配置
    volatile
  • 原文地址:https://www.cnblogs.com/2021-yanghaoran/p/12930029.html
Copyright © 2020-2023  润新知