P1582 倒水 (數學)

P1582 倒水

題目描述

一天,CC買了N個容量能夠認爲是無限大的瓶子,開始時每一個瓶子裏有1升水。接着~~CC發現瓶子實在太多了,因而他決定保留不超過K個瓶子。每次他選擇兩個當前含水量相同的瓶子,把一個瓶子的水所有倒進另外一個裏,而後把空瓶丟棄。(不能丟棄有水的瓶子)c++

顯然在某些狀況下CC沒法達到目標,好比N=3,K=1。此時CC會從新買一些新的瓶子(新瓶子容量無限,開始時有1升水),以到達目標。數組

如今CC想知道,最少須要買多少新瓶子才能達到目標呢?ui

輸入輸出格式

輸入格式:spa

一行兩個正整數, N,K(1\le N\le 2\times 10^9,K\le 10001≤N≤2×109,K≤1000)。code

輸出格式:get

一個非負整數,表示最少須要買多少新瓶子。數學

輸入輸出樣例

輸入樣例#1:it

3 1io

輸出樣例#1:class

1

輸入樣例#2:

13 2

輸出樣例#2:

3

輸入樣例#3:

1000000 5

輸出樣例#3:

15808

Soltuion

這道題要麼你須要對很好的數學思惟(能夠一眼看出),要麼你就須要舉例子

蒟蒻固然是選擇第二種

如下咱們列出每一行的第一個數爲最開始的瓶子個數,第二行爲合併後最少的瓶子個數,第二個數爲它合併前的瓶子個數的二進制

1 1 0001
2 1 0010
3 2 0011
4 1 0100
5 2 0101
6 2 0110
7 3 0111
8 1 1000
...

咱們發現合併後的瓶子個數就是合併前瓶子個數的二進制下1的個數,如今問題就轉化成了如何求出一個數的二進制下1的個數

暴力求會T,那麼怎麼快速求出呢?

樹狀數組都會吧,還記得\(lowbit(x)\)?咱們能夠用\(x\&-x\)求出一個數從後往前數第一個1的位置,就用這個來求

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
#define il extern inline
#define rg register
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lol long long
using namespace std;

const int N=1e7+10;

int read() {
    lol ans=0, f=1; char i=getchar();
    while (i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while (i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48), i=getchar();
    return ans*f;
}

int lowbit(int x) {return x&-x;}

int cal(int x,int ans=0) {
    while(x) x-=lowbit(x),ans++;
    return ans;
}

int main()
{
    int n,k,ans=0;
    in(n), in(k);
    while(cal(n)>k) ans+=lowbit(n),n+=lowbit(n);
    cout<<ans<<endl;
}
相關文章
相關標籤/搜索