Educational Codeforces Round 44 (Rated for Div. 2) D. Sand Fortress
阿新 • • 發佈:2018-12-19
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; }