Sand Fortress CodeForces - 985D (二分枚举答案+等差数列的求和)

https://blog.csdn.net/weixin_39453270/article/details/80433626
参考了Chen_Jr_dalao的博客!!!!!!(附上我一点浅显的理解)
D. Sand Fortress
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are going to the beach with the idea to build the greatest sand castle ever in your head! The beach is not as three-dimensional as you could have imagined, it can be decribed as a line of spots to pile up sand pillars. Spots are numbered 1 through infinity from left to right.

Obviously, there is not enough sand on the beach, so you brought n packs of sand with you. Let height hi of the sand pillar on some spot ibe the number of sand packs you spent on it. You can't split a sand pack to multiple pillars, all the sand from it should go to a single one. There is a fence of height equal to the height of pillar with H sand packs to the left of the first spot and you should prevent sand from going over it.

Finally you ended up with the following conditions to building the castle:

  • h1 ≤ H: no sand from the leftmost spot should go over the fence;
  • For any  |hi - hi + 1| ≤ 1: large difference in heights of two neighboring pillars can lead sand to fall down from the higher one to the lower, you really don't want this to happen;
  • : you want to spend all the sand you brought with you.

As you have infinite spots to build, it is always possible to come up with some valid castle structure. Though you want the castle to be as compact as possible.

Your task is to calculate the minimum number of spots you can occupy so that all the aforementioned conditions hold.

Input

The only line contains two integer numbers n and H (1 ≤ n, H ≤ 1018) — the number of sand packs you have and the height of the fence, respectively.

Output

Print the minimum number of spots you can occupy so the all the castle building conditions hold.

Examples
input
Copy
5 2
output
Copy
3
input
Copy
6 8
output
Copy
3
Note

Here are the heights of some valid castles:

  • n = 5, H = 2, [2, 2, 1, 0, ...], [2, 1, 1, 1, 0, ...], [1, 0, 1, 2, 1, 0, ...]
  • n = 6, H = 8, [3, 2, 1, 0, ...], [2, 2, 1, 1, 0, ...], [0, 1, 0, 1, 2, 1, 1, 0...] (this one has 5 spots occupied)

The first list for both cases is the optimal answer, 3 spots are occupied in them.

And here are some invalid ones:

  • n = 5, H = 2, [3, 2, 0, ...], [2, 3, 0, ...], [1, 0, 2, 2, ...]

  • n = 6, H = 8, [2, 2, 2, 0, ...], [6, 0, ...], [1, 4, 1, 0...], [2, 2, 1, 0, ...】

题意:你有n袋沙子,你需要用沙子在二维数轴上堆一面墙,沙子必须摆放在整数的位置,最左边已经有一面高为h袋沙子的墙了,所以,你的最左边的沙子的袋数不能大于h,并且,相邻的两个点上所堆放的沙子的袋数相差不能超过1。最后的一堆的沙子的袋数一定是1,问,怎样堆放才能使沙子的堆数最小。

思路:可以发现,我们堆出来的的沙子的高度有一下两种情况,①从h到1的单调递减的数列②从h先单调递增到一个最大值,然后单调递减的数列。我们可以用二分来枚举区间的长度,然后,检查这个长度是否合理。即判断,在该堆数下,用n袋沙子是否可以建成上面所说的两种情况的墙。需要注意的是,第二种情况下,存在有两个最大值的情况,需要特殊处理一下,详细见代码即注释。

//相邻的差为1,那么,最后一个的高度一定是1!!!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,h;
const ll cnt=2000000000;
bool check(ll x){
    if(x<=h){//如果堆数小于等于h那么,所占的沙堆的的高度一定是一个单调递减的数列!才能使得所占堆数最小
        if(x>=cnt) return true;
        return x*(x+1)/2>=n;//如果总堆数的沙袋之和小于n,那么说明该种方案所需的沙袋不足n,所以,要放更多的堆数,否则的话,说明可能有更小的方案
    }
    //如果所分的堆数大于h的话,说明沙堆的高度是一个先增加,后减小的数列
    //那么,使得沙堆数最小的方案一定是从高为h开始,先增后减
    ll a=(x-h)/2+h;//所能达到的最高值
    if(a>=cnt) return true;
    if((x-h)%2!=0)//注意,如果是奇数的话,就会有两个最大值  (x-h)表示的是从h递增到最大值,然后递减到h所需的沙堆数注意,这里不包括h,因为,h是已有的一个沙堆!!
        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()
{
    cin>>n>>h;
    ll ln=1,rn=n;
    while(ln<=rn){
        ll mid=(ln+rn)>>1;
        if(check(mid)) rn=mid-1;
        else ln=mid+1;
    }
    cout<<rn+1<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_41874469/article/details/80472641