題目
試題1:杯子 (glass)
源代碼:glass.cpp
輸入文件:glass.in
輸出文件:glass.out
時間限制:1s
空間限制:256MB
題目描述
小明買了N個容積可以是無窮大的杯子,剛開始的時候每個杯子里有1升水,接着小明發現杯子實在太多了,於是他決定保留不超過K個杯子。每次他選擇兩個當前含水量相等的 杯子,把一個杯子的水全部倒進另一個里,然后把空瓶丟棄。(不能丟棄有水的杯子)
顯然在有些情況下小明無法達到他的目標,比如N=3,K=1。此時小明會重新買一些新的杯子(新杯子容積無限,開始時有1升水), 以達到目標。
現在小明想知道,最少需要買多少個新杯子才能達到目標呢?
輸入說明
一行兩個正整數,N,K(1≤N≤1000000000,K≤1000)。
輸出說明
一個非負整數,表示最少需要買多少新杯子。
樣例輸入1
3 1
樣例輸出1
1
樣例輸入2
13 2
樣例輸出2
3
樣例輸入3
1000000 5
樣例輸出3
15808
數據范圍
對於50%的數據,N≤10000000;
對於100%的數據如題目。
分析
由於是第一題,而且數據極大(o(n)也做不了),所以這道題要么是貪心,要么是數論,要么是貪心+數論。
仔細閱讀題目,你就會發現每一個杯子(除了剛開始的杯子)里的水量都是由兩個相等的水量相加而得。
所以每一個杯子里的水量都是2x(x為非負整數),進而我們知道每2y個水量為1杯子可以變成1個杯子(這一個杯子里的水量為2y)。
為了使新添的杯子數量最少,所以我們每次要讓y最大(貪心)。
注意:為了避免數值過大,所以最好用long long
代碼
#include<iostream>
using namespace std;
long long n,k,sum=1;
int main()
{
cin>>n>>k;
if(k>=n)
{
cout<<"0";
return 0;
}
long long t=1;
while(sum<=n) sum<<=1;//"<<"是位運算,和"*2"一樣
long long a=sum>>1;
while(t<k)//循環k-1次
{
while(a>n) a>>=1;//">>"也是位運算,和"/2"一樣
n-=a;
t++;
}
sum=1;
while(sum<=n) sum<<=1;//計算需要用幾個水量為1杯子才能將剩下的所有杯子變成一個杯子
cout<<sum-n;
return 0;
}
