CodeForces 985D Sand Fortress (二分)
阿新 • • 發佈:2018-12-23
題意:給你n個沙包和一個h(後面又說h的用處),要求堆一面沙牆(這面沙牆由很多高矮不一的沙堆組成,沙堆的高度由沙袋數量決定,即一個二維問題),求最少的沙堆數量建出題目要求的沙牆。
沙牆要求:1.第一根沙堆的高度不能超過h ;
2.任意兩根沙堆的高度差不能超過1(即最後一個沙堆高度一定為1) ;
3.沙牆的所有沙堆消耗的沙袋總數為n;
題解:從題目意思可以發現這裡分為3種情況,
第一種是這麼堆:K(K<=h),K-1,K-2,...,2,1 = n ;
第二種
第三種是這麼堆:K(K>h),K+1,...,K+x-1,K+x,K+x,K+x-1,...,K,K-1,...,2,1 = n;
由於考慮到要找最少的堆數目,我們可以使用二分答案的辦法來解決,二分縮小範圍的原理是堆mid個沙堆所能堆出的沙牆使用最多的沙袋的數目是否大於題目給出的n,若是有說明我們可以嘗試縮小範圍,得到更小堆得數目從而求得題目要的最小值。
至於二分的範圍由數學的等差數列求和公式知道,R_max=2*sqrt(1e18) 左右 ,別取太大任意在乘法運算爆longlong,還有除2,可以用等式另一邊乘2代替。
程式碼如下:
#include<iostream> #include<cmath> #include<string> #include<cstring> #include<cstdio> #include<time.h> #include<algorithm> #include<vector> #include<map> using namespace std; #define ll long long #define inf 0x3f3f3f3f const int maxn = 1e5 + 500; ll n, h; bool ok(ll x) {//這裡判斷求得的是長度為x的沙牆最多能堆放的沙包個數是否大於n if (x <= h) //x+(x-1)+...+3+2+1 return x *(x + 1) >= 2*n ? true : false; else {//h+(h+1)+...+(h+k-1)+(h+k)+...+(h+1)+h+(h-1)+...+2+1 或 h+(h+1)+...+(h+k-1)+(h+k)+(h+k-1)+...+h+...+2+1 ll t = x - h; if (t % 2) return (1 + h + t / 2)*(h + t / 2) + (h + h + t / 2)*(t / 2 + 1) >= 2 * n ? true : false; else return (1 + h + t / 2)*(h + t / 2) + (h + h + t / 2 - 1)*t / 2 >= 2 * n ? true : false; } } int main() { while (~scanf("%lld%lld", &n, &h)) { ll l = 1,r = 2*inf; while (l<=r-1){//二分ans ll mid = (l + r) >> 1; if (ok(mid)) r = mid; else l = mid+1; } cout << l << endl; } return 0; }