【t088】倒水

来源:互联网 发布:java sock5 编辑:程序博客网 时间:2024/06/11 00:40

Time Limit: 1 second
Memory Limit: 128 MB

【问题描述】

一天辰辰买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着辰辰发现瓶子实在太多了,于是他决定保留不超
过K个瓶子,每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃(不能丢弃有水的瓶
子)。 显然在某些情况下辰辰无法达到目标,比如N=3,K=1。此时辰辰会重新购买一些新的瓶子(新瓶子容量无限,开始时有1升水)
以达到目标。
现在辰辰想知道最少需要多少新瓶子才能达到目标呢?
【数据规模】
对于50%的数据,n<=10^7;对于100%的数据如题目。
【提示】考虑lowbit运算
【输入格式】

输入文件一行两个正整数N和K,其中1<=n<=10^9,k<=1000。

【输出格式】

输出文件包含一个非负整数,表示最少需要购买的瓶子数量。

Sample Input

3 1
Sample Output

1

Sample Input2

13 2
Sample Output2

3

Sample Input2

1000000 5
Sample Output2

15808

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=t088

【题解】

首先把n转换成二进制;
这个n能够分成的最小的水的数量就为二进制中1的个数;
因为2^x的水能够合成1瓶水;
然后考虑这样的形式
1 0 1 1 1 0
如果想让1的个数变少一点;
可以考虑加上最低位的1对应的数字这里即2
然后就会变成
1 1 0 0 0 0
这样做最少能保证消掉一个0、加上1个0,而且可能会有上面的消除多个0的情况,所以肯定不会变差(1的个数肯定不会变多);
一直重复上述过程直到1的个数小于等于k就好
(如果写过树状数组就知道lowbit操作了x&(-x)就是获取最低的1对应的数字)

【完整代码】

#include <cstdio>#include <algorithm>#include <cmath>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define LL long long#define rep1(i,a,b) for (int i = a;i <= b;i++)#define rep2(i,a,b) for (int i = a;i >= b;i--)#define mp make_pair#define pb push_back#define fi first#define se second#define rei(x) scanf("%d",&x)#define rel(x) scanf("%I64d",&x)typedef pair<int,int> pii;typedef pair<LL,LL> pll;const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};const double pi = acos(-1.0);const int MAXN = 100;int n,k;int cnt = 0,ans = 0;int get_num(int n){    cnt = 0;    while (n)    {        cnt+=(n&1);        n>>=1;    }    return cnt;}int main(){    //freopen("F:\\rush.txt","r",stdin);    rei(n);rei(k);    while (get_num(n)>k)    {        ans+=(n&(-n));        n=n+(n&(-n));    }    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击