一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)
显然在某些情况下CC无法达到目标,比如N=3,K=1。此时CC会重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以到达目标。
现在CC想知道,最少需要买多少新瓶子才能达到目标呢?
输入输出格式
输入格式:
一行两个正整数, N,K(1≤N≤2×109,K≤1000)。
输出格式:
一个非负整数,表示最少需要买多少新瓶子。
输入输出样例
输入样例#1:
3 1
输出样例#1:
1
输入样例#2:
13 2
输出样例#2:
3
输入样例#3:
1000000 5
输出样例#3:
15808
思路:读完题的反应是二叉树补全,问题转化成k棵树,求节点差。emm能得50分,再看题发现瓶只有1L水,只能丢空的,那补全做法就有问题了。重新转化一下问题,总瓶子一定与2的次幂有关,然后把瓶子个数转化成2进制会发现
合并前 | 二进制 | 合并后 |
---|---|---|
1个瓶子 | 1 | 1个瓶子 |
2个瓶子 | 10 | 1个瓶子 |
3个瓶子 | 11 | 2个瓶子 |
4个瓶子 | 100 | 1个瓶子 |
5个瓶子 | 101 | 2个瓶子 |
6个瓶子 | 110 | 2个瓶子 |
7个瓶子 | 111 | 3个瓶子 |
8个瓶子 | 1000 | 1个瓶子 |
... | ... | ... |
所以,就直接对1所在的位置进行操作即可,判断每个位置是否存在可合并的即可。
代码如下:
#include<set>
#include<map>
#include<list>
#include<deque>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<stdio.h>
#include<sstream>
#include<stdlib.h>
#include<string.h>
//#include<ext/rope>
#include<iostream>
#include<algorithm>
#define pi acos(-1.0)
#define INF 0x3f3f3f3f
#define per(i,a,b) for(int i=a;i<=b;++i)
#define LL long long
#define swap(a,b) {int t=a;a=b;b=t}
using namespace std;
//using namespace __gnu_cxx;
queue<int>q;
int n,k,m,x=1,s;
int main()
{
cin>>n>>m;
while(n!=0)
{
if(n&1)
{
k++;//1的个数
q.push(x);
}
x<<=1;//翻倍移位
n>>=1;//减半移位
}
int a=q.front();
q.pop();
while(k>m)
{
while(q.front()!=a)//无可合并的
{
s+=a;
a<<=1;
}
while(q.front()==a)//可合并的
{
a<<=1;
q.pop();
k--;
}
}
printf("%d",s);
return 0;
}