LJY Codes

代码改变世界!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

经典例题(一)——倒水

Posted on 2017-11-03 23:31  hzzxLJY  阅读(607)  评论(0编辑  收藏  举报

经典例题(一)——倒水

【题目描述】

小张买了n个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着,小张觉得瓶子实在太多了,于是他决定保留不超过k个瓶子。每次他选择两个当前含水量相同的瓶子合并,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)

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

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

【输入文件】

 一行两个正整数,n,k(1<=n<=109k<=1000)。

【输出文件】

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

【样例输入】

3 1

【样例输出】

1

【数据规模】

对于30%的数据,n<=3*10^5

对于100%的数据如题目。

 

做完了再去看:

【解题思路】

  定义一些变量什么的。就不再赘述了,直接上代码。

var n,t,i,j,k,x,y:longint;
    a:array[0..51] of longint;

 

  首先,举几个例子试一试。不难发现,若n为2a时一个多的都不用。

Function check_sit:boolean;
var nn:longint;
begin
  nn:=n;
  if nn=1 then 
    begin
      write('0');
      close(input);
      close(output);
      halt;
    end;
  while nn<>1 do
    begin
      if (nn<>1) and odd(n) then exit(False);
      nn:=nn div 2;
    end;  
end;

其他情况要好好思考了,其实也是可以看出一些规律来的。比如带一个数13;

发现13=1+4+8,所以可以联想到2进制,即(13)10=(1101)2

代码如下:

Procedure doit;
begin
k:=n;
while k>0 do
      begin
      x:=x+1;
      a[x]:=k mod 2;
      k:=k div 2;
      end;
k:=0;
for i:=x+1 downto 1 do
    begin
    if (a[i]=0)and(k<=t-1) then y:=i;
    if a[i]=1 then k:=k+1;
    end;
if k<=t
   then writeln(0)   //寻找二进制中最靠前的0,然后将这个0改为1并将这个0之后的一段截取并转换为十进制s。算出一个最接近并且大于这个数的2的幂次m,用m减去s,即为答案
   else begin
        k:=1 shl (y-1);
        x:=k-n mod k;
        writeln(x);
        end;
end;

 

接下来不用多说了,就剩下调用子程序了,上主程序:

Begin
  assign(input,'water.in');
  assign(output,'water.out');
  reset(input);
  rewrite(output);
  readln(n,t);
  if not check_sit then doit else write('0');    //注意:如果是2的幂则输出True否则输出False,因为这里是启动一般情况的子程序,所以当check_sit返回False执行即可 
  close(input);close(output);
End.

 测试数据相关:【提供数据量最大的一组】

In:536870919 1

Out:536870905

 

想抄标程的同学们:我没有设置障碍,只要从上往下把几个程序段连起来就是本题的AC程序。