杯子

杯子

题目

小明买了 N N N个容积可以是无穷大的杯子,刚开始的时候每个杯子里有 1 1 1升水,接着小明发现杯子实在太多了,于是他决定保留不超过 K K K个杯子。每次他选择两个当前含水量相等的杯子,把一个杯子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的杯子)

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

现在小明想知道,最少需要买多少个新杯子才能达到目标呢?

输入

一行两个正整数, N N N K K K

输出

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

样例输入1

3 1

样例输出1

1

样例输入2

13 2

样例输出2

3

样例输入3

1000000 5

样例输出3

15808

数据范围

对于 50 % 50% 50的数据, N ≤ 10000000 N≤10000000 N10000000
对于 100 % 100% 100的数据, 1 ≤ N ≤ 1000000000 1≤N≤1000000000 1N1000000000 K ≤ 1000 K≤1000 K1000

思路

这道题其实就是一道模拟题。
由题目可以看出,杯子里水的重量一定是二的某个次方,那么就可以得出我们所有的水是由 K K K个二的次方数加起来构成的。
那么我们就可以先把n拆成二的次方数,看看杯数是否超过了 K K K
如果没有,就可以输出零(不需要加杯子);否则,我们先找出最 K K K大的数,然后在这 K K K个数之中找到最小的那个,把它乘二。这样,就会多出一些,我们把多出的求出来,就是答案了。

代码

#include<cstdio>
#define ll long long
using namespace std;
ll n,k,a=1,b[2][1001],bei;
bool yes;
int main()
{
	scanf("%lld%lld",&n,&k);//读入
	while (a<=1000000000)//预处理出二的很多次方
	{
		b[0][++b[0][0]]=a;
		if ((a<<1)>n&&!yes)
		{
			yes=1;
			b[1][0]=b[0][0];//求出n在哪个数的刚好前面(也就是说那个数除以二就比n小)
		}
		a*=2;
	}
	int nn=n;
	for (int i=b[1][0];i>=1;i--)//把n拆成许多二的次方的数(直到拆出来的数超过了目标数)
	 while (b[0][i]<=nn&&bei<k)
	 {
		nn-=b[0][i];
		b[1][i]++;
		bei++;
		if (!nn) break;
	 }
	if (!nn) printf("0");
	else
	for (int i=1;i<=b[0][0];i++)
	 if (b[1][i])//找到被拆出来的最小的数
	 {
	 	printf("%d",b[0][i]-nn);//输出多出来的数(即是要买的新杯子)
	 	break;
	 }
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值