• 倒水


    一、倒水

    【题目描述】

    一天,树树买了N个容量可以认为是无限大的瓶子,初始时每个瓶子里有1水。树树发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子合并,把一个瓶子的水全部倒进另一个瓶,然后把空瓶丢弃(不能丢弃有水的瓶子)。

    显然在某些情况下树树无法达到目标,比如N=3K=1。此时树树会重新买一些新的瓶子(新瓶子容量无限,开始时有1水),以达到目标。

    现在树树想知道,最少需要买多少新瓶子才能达到目标呢?

    【输入】

         一行两个正整数NK1≤N≤109    K1000);

    【输出】

       一个非负数,表示最少需要买多少新瓶子。

    【样例输入】

    3 1
    【样例输出】
    1

    【数据规模】

    对于30%的数据,N≤3*105

    对于100%的数据,1≤N≤109  K1000

    分析:

        n可以表示为二进制相加的形式: n=2^x1+2^x2+2^x3+......2^xm    (x1<x2<x3<......<xm),即,n转换为二进制数里有m个1则此时最少要保留m个瓶子。

       如果M<k,则不需要新瓶子。

      如果M>k,则首先消掉二进制中最低位(x1+1)位的1,则需要添加2^x1个新瓶。依次类推直到二进制中“1”的个数减少到K个或以下停止。

      求某个十进制下的数字在二进制下有多少个“1”,可以用不断减lowbit的方法来求。

      假设n的二进制中最后一个“1”的位置为右数第(x1+1)个,则lowbit(n)=2^x1。

      n的lowbit可以用  n and (-n)求出来

     因为:在计算机系统中,数值一律用补码来表示和存储。正整数的补码与原码相同,求负整数的补码,符号位不变,数值位各位取反,最后整个数加1。

    比14的补码为00001110,;-14的补码为11110001+1=11110010;则14 and(-14)=00000010

    //x and (-x) 取二进制的最末位
    var
      n,k,t,j,i,ans:longint;
      a:array[1..100] of integer;
    
      function solve(n:longint):longint;
      var num:longint;
      begin
        num:=0;
        while n>0 do
          begin
            n:=n-(n and(-n));
            inc(num);
          end;
        exit(num);
      end;
      function power(x:longint):longint;
      var sum:integer;
      begin
        for i:=1 to x do sum:=sum*2;
      end;
    begin
      assign(input,'water.in');reset(input);
      assign(output,'water.out');rewrite(output);
      readln(n,k);
      ans:=0;
      while  solve(n)>k do
        begin
          ans:=ans+(n and (-n));
          n:=n+(n and (-n));
        end;
        writeln(ans);
      close(input);close(output);
    end.
    View Code
  • 相关阅读:
    js 每个月有多少天算法
    js 树的操作
    画线
    程序员如何防止脑疲劳
    汉字求出拼音缩写
    datagird 多行外于编辑状态
    overflow: hidden 失效
    CSS 相对/绝对(relative/absolute)定位系列(三)
    display:inlineblock在Chrome与FF下导致的间隙
    css ul li 的使用及浏览器兼容问题
  • 原文地址:https://www.cnblogs.com/ssfzmfy/p/3959429.html
Copyright © 2020-2023  润新知