P1582-倒水

一天,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个瓶子11个瓶子
2个瓶子101个瓶子
3个瓶子112个瓶子
4个瓶子1001个瓶子
5个瓶子1012个瓶子
6个瓶子1102个瓶子
7个瓶子1113个瓶子
8个瓶子10001个瓶子
.........

所以,就直接对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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值