杯子
题目
小明买了 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
N≤10000000;
对于
100
%
100%
100%的数据,
1
≤
N
≤
1000000000
1≤N≤1000000000
1≤N≤1000000000,
K
≤
1000
K≤1000
K≤1000。
思路
这道题其实就是一道模拟题。
由题目可以看出,杯子里水的重量一定是二的某个次方,那么就可以得出我们所有的水是由
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;
}