食物大放送 aqx

Jeanny發表於2024-08-16

題目描述 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;
}

相關文章