題目描述 0.5s 512MB
小明是某個遊戲中糧倉的管理者,糧食在過冬的時候被老鼠吃掉了好多,因此對不上賬了。可是馬上領導就要來檢查了,小明很慌張。
糧倉裡面一共有\(n\)堆糧食,第\(i\)堆糧食按賬目上的數量,應該有\(a_i\)斤。
但是現在每一堆糧食都只剩下\(1\)斤了。
於是小明決定祭出自己的終極武器:糧食放大器。
具體地:小明每次可以使用一個從付費商城購買的糧食放大器,然後對區間\([l,r]\)使用,使用後,區間\([l,r]\)裡的每一堆糧食,要麼\(+1\)斤,要麼\(\times 2\),這個小明可以自主決定(也就是,每一堆可以自主的選擇\(+1\)或者\(\times 2\))。
由於糧食放大器很貴,所以小明決定儘量少的購買糧食放大器。
請幫助小明算一下,他最少要購買多少個糧食放大器,才能完成目標。
請注意,小明必須把每一堆糧食恰好變成\(a_i\)。
輸入格式
第一行輸入\(n\)。
第二行輸入\(n\)個正整數,表示\(a_1,...,a_n\)。
輸出格式
輸出答案在單獨的一行。
樣例輸入 #1
1
101
樣例輸出 #1
9
樣例輸入 #2
3
3 2 3
樣例輸出 #2
3
樣例輸入 #3
10
3 1 3 100 13 2 14 3 5 14
樣例輸出 #3
17
資料範圍
對於10%的資料:\(n\leq 1,a_i\leq 10^6\)。
對於25%的資料:\(n\leq 1\)。
對於60%的資料:\(n\leq 50000\)。
對於70%的資料:\(n\leq 10^5\)。
對於80%的資料:\(n\leq 2\times 10^5\)。
對於100%的資料:\(1\leq n\leq 10^6,1\leq a_i\leq 10^{18}\)。
analysis:
求出每個數字的最大次數和最小次數,讓他們儘可能接近,畫圖可以分析出來,如果前面的數字確定下來是x次,下一個數字如果上下界如果包含x,則當前數字的次數也是x,如果不包含,下界大於x,則取下界,上界小於x,則取上界。
obstacle:當前數字區間和前一個數字區間做比較,就傻了,應該和前一個已經確定的數字x做比較。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,b[2000005], ans;
int cal(ll x){
ll cnt = 0;
while(x > 1){
cnt++;
if(x & 1 == 1) x -= 1;
else x >>= 1;
}
return cnt;
}
struct Node{
ll l, r;
}a[2000005];
int main(){
cin>>n; ll x;
for(int i = 1; i <= n; i++){
cin>>x;
a[i].r = x-1;
a[i].l = cal(x);
// cout<<"pp: "<<i<<" "<<a[i].l<<" "<<a[i].r<<endl;
}
if(n == 1) {
cout<< a[1].l;
return 0;
}
if(a[2].l >= a[1].r){
b[2] = a[2].l, b[1] = a[1].r;
}
else if(a[2].r < a[1].l){
b[2] = a[2].r, b[1] = a[1].l;
}
else if(a[2].r <= a[1].r)
b[2] = a[2].r, b[1] = a[2].r;
else if(a[2].l >= a[1].l)
b[2] = a[2].l, b[1] = a[2].l;
// cout<<"b: "<<b[1]<<" "<<b[2]<<endl;
for(int i = 3; i <= n; i++){
if(a[i].l <= b[i-1] && a[i].r >= b[i-1])
b[i] = b[i-1];
else if(a[i].l > b[i-1])
b[i] = a[i].l;
else if(a[i].r < b[i-1])
b[i] = a[i].r;
}
// cout<<"b: "<<b[3]<<endl;
for(int i = 1; i <= n; i++){
ll y = b[i] - b[i-1];
if(y > 0) ans += y;
}
cout<<ans<<endl;
return 0;
}