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 Output1
Sample Input2
13 2
Sample Output23
Sample Input2
1000000 5
Sample Output215808
【题目链接】:
【题解】
首先把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#include #include 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 pii;typedef pair 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;}