1. 程式人生 > >Educational Codeforces Round 44 (Rated for Div. 2) D. Sand Fortress

Educational Codeforces Round 44 (Rated for Div. 2) D. Sand Fortress

n堆沙子,最左邊的沙子的最大高度不能超過H,讓你在一個從1到正無窮的一維平面內放沙子,且要滿足相鄰兩個座標的沙子的高度不能超過1。問所需要的最小長度。

題目要求相鄰兩個座標的沙子的高度不能超過1,那麼左右邊的那堆沙子高度肯定是1,所以沙子的擺放方式有兩種,一種是從高度為H遞減(每次-1),另一種是先增後減,像一個山的形狀。可以發現每個部分都是一個d=1的等差數列。分析之後,就可以二分長度了。但要注意的是等差數列求和是x*(x+1)/2,因為資料n最大為1e18,所以右邊界必須自己設定一個比如2e9,不然右邊界直接用n是肯定會爆long long的。

1,當列舉長度 x<=H 時:最優的擺放是一個遞減的等差數列,這樣放的沙包最多(不理解可以畫圖看看

2,當列舉長度 x>H 時:最優的擺放肯定就是一個山的形狀了,但要當心當x-H為奇數的情況,最高點有兩個並列的

     當H為3時,x=6:H 3 4 4 3 2 1 ,x=7 :H 3 4 5 4 3 2 1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e5+5;
const ll cnt=2e9;
ll n,H;
bool check(ll x) {
	if(x<=H) {
		return x*(x+1)/2>=n;
	} 
	else {
		ll a=(x+H)/2;
		if((x-H)%2!=0)
			return a*(a+1)/2+(a+H)*(a+1-H)/2>=n;//奇數
		return a*(a+1)/2+(a-1+H)*(a-H)/2>=n;//偶數
	}
}
int main() {
	scanf("%lld%lld",&n,&H);
	ll le=0,ri=min(n+1,cnt);
	while(ri>le) { //二分長度
		ll mid=(le+ri)>>1;
		if(check(mid))
			ri=mid;
		else le=mid+1;
	}
	cout<<le<<endl;
	return 0;
}