【题解】 Test 买水的ACX(套路)

时间:2023-03-09 07:29:52
【题解】 Test  买水的ACX(套路)

题目描述:

ACX在××信竞组学会信息竞赛,但是他的同学都很巨,于是要他去买水,结果来到某个买水的商店(奇奇怪怪的商店)。

一天,ACX买了 N 个容量可以认为是无限大的瓶子,初始时每个瓶子里有 1 升水。

ACX发现瓶子实在太多了,于是他决定 保留不超过 K 个瓶子。每次他选择两个当前含水量相同的瓶子合并,把一个瓶子的水全部倒进另一个瓶,然后把空瓶丢弃(不能丢弃有水的瓶子)。

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

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

读入格式:

一行 两个正整数 N,K(1<=N<=10^9 ,K<=1000)

输出格式:

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

样例输入:

3 1

样例输出:

1

Solution:

将瓶子中水的体积转换成二进制,如1升可写成0000001,同理两升就是0000010。

题目合并的一定是相同的体积合并,所以容积一定是二的次方倍,这时候我们可以发现,二进制数上的1就可以是一个瓶子,这时候我们就可以将题目转换成加数(数就是多加了几瓶水),如样例:11 加一变成 100 就只有一个瓶子了。

所以题目就可以变成每次加x,使这个数二进制时位上的1的个数小于k

为了方便我们每次就加上最后一位上表示的二进制数如10010(2)时,就加10(2),使最后位置上的1进位从而减少1的个数。

这个题目需要感性理解下吧,理解代码了还是不难的。就是一道套路题~

Code:

 //It is coded by Ning_Mew on 11.1 :)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,k;
int need=;
int a[+];
int num(int s){
int numb=;
while(s){numb++;s=s-(s&(-s));}
return numb;
}
int main(){
freopen("water.in","r",stdin);
freopen("water.out","w",stdout);
scanf("%d%d",&n,&k);
while(num(n)>k){
need+=(n&(-n));
n+=(n&(-n));
}
printf("%d\n",need);
return ;
}