Sand Fortress CodeForces - 985D ( 二分法 )

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SEVENY_/article/details/83187244

Sand Fortress 

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 i be 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

5  2

Output

3

Input

6  8

Output

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堆沙子,在一个从1到正无穷的一维平面内放沙子来堆成一面墙,最左边的沙子的最大高度不能超过给定的H,且要满足相邻两个坐标的沙子的高度差不能超过1。问怎样堆放沙子能够占用的最少坐标点的个数。

因为题目要求相邻两个坐标的沙子高度差不能超过1,这代表最后一堆沙子的个数必定为1。

可以发现,我们堆出来的的沙子的高度曲线会有两种情况:①从h到1的单调递减的数列。②从h先单调递增到一个最大值,然后单调递减的数列。

当堆数<=h时,为第一种单调递减的情况,例如h=8,堆数=7. 那么高度的曲线就可以是一直递减到最右边沙堆高度为1为止。

当堆数>h时,为第二种单调递减的情况,例如h=8,堆数=10,那么高度的曲线就不能一直递减,因为如果一直递减的话,从8递减到1也只有8堆,所以曲线应该是先递增再递减。

我们可以用二分来枚举可能占用的坐标点个数,l初始为1,最少放成1堆,r初始为n,最多放成n堆。然后,进行二分,mid=(l+r)/2,检查这mid长度是否合理。即判断,在该堆数下,用n袋沙子是否可以建成上面所说的两种情况的墙。需要注意的是,第二种情况下,如果mid为奇数堆,那么会存在有两个最大值的情况。

还有一点要注意的就是最大值堆的取值范围:

因为n的值<=1e18,根据等差序列求和公式来看, 需要(a+1)*a/2<=n 
所以我们就要找我们二分出来的堆数最大值。
每堆沙袋数是从1增加到最大值,然后再递减到1. 这样得到的堆数是最大的。
所以形成的堆形状就如下图所示:


假设堆数是k,那么最大值就是k/2,根据等差数列求和公式,沙袋总和分为两部分来求:
第一部分是从1增加到最大值k/2的序列和,第二部分是从最大值k/2递减到1的序列和。
两部分和相加再减去多加了一次的最大值。

那么我们所得出的堆数必须要<=2*1e9 。如果>2*1e9,在求和之后就会爆longlong,并且也不符合题意。

所以对于在以下代码中的当堆数>cnt时,都会直接返回1,再进行二分。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
long long cnt=2000000000; 
long long n,h;
int check(long long x)
{   //堆数x<=h,说明所占的沙堆的高度从h开始一直是单调递减的数列,才使得所占的堆数最少
	if(x<=h)
	{
		if(x>cnt)return 1;
		else return x*(x+1)/2>=n;//等差数列求和公式。(首项+尾项)*项数/2. 
	} 
	//如果堆数x>h,说明沙堆高度一定是先增加后减少
	//那么堆数最少一定是从高度h开始增加到最大值然后减少一直到1 
	//(x-h)表示的是从h递增到最大值,然后再递减到h所需的沙堆数。 
	//注意,这里不包括h,因为,h是一定要存在的最左边的固定的已有的一个沙堆! 
	long long a=(x-h)/2+h;//最大值 
	if(a>cnt)return 1;
	if((x-h)%2!=0)//如果(x-h)是奇数的话,就会有两个最大值
	//等差数列求和来求沙袋总数。两部分组成 
	//一部分是最大值a递减到1的和。首项是a,尾项1,项数a。 
	//一部分是h增加到最大值a的和。首项h,尾项a,项数a-h+1。 
        return a*(a+1)/2+(a+h)*(a+1-h)/2>=n;//有两个最大值
        return a*(a+1)/2+(a+h)*(a+1-h)/2-a>=n;//有一个最大值 
}
int main()
{
	scanf("%lld%lld",&n,&h);
	long long l=1,r=n;
	while(l<=r)
	{
		long long mid=(l+r)/2;
		if(check(mid))
		  r=mid-1;
		else
		  l=mid+1;
  	}
  	cout<<r+1<<endl;
	return 0;
 } 

例子分析: 

例:n=6,h=8.

l=1,r=6; mid=(1+6)/2=3;  mid=3<8, 所以曲线为一直单调递减。堆数为3,最右边的必须是1,那么要在这3堆上放最多的沙袋,序列一定是3,2,1.总堆数就是用等差数列求和公式来求。(首项+尾项)*项数/2.得到(1+3)*3/2=6,所以3堆可以放下6袋沙子。

l=1,r=mid-1=2;l<r,继续二分。mid=(1+2)/2=1<8,那么曲线为一直单调递减,堆数为1,那么就只能放1个沙袋,所以1堆放不下6袋沙子。

l=mid+1=2,r=2;l=r,继续二分。mid=(2+2)/2=2<8,那么曲线为一直单调递减,堆数为2,那么要放最多的沙堆为:2,1。(1+2)*2/2=3,只能放3个沙袋,所以2堆放不下6袋沙子。

l=mid+1=3,r=2;l>r。结束二分。

堆数为r+1=3堆。

例:n=9,h=2.

l=1,r=9,mid=(1+9)/2=5;mid=5>2,所以曲线一定是先增加后递减。因为曲线要先增加,那么曲线的最左边的堆数一定是h,然后从h开始增加,(mid-h)表示的是从h递增到最大值,然后再递减到h所需的沙堆数。(5-2)=3,那么就说明h之后增加再递减到h的堆数有3堆(不包括h),那么增加到的最大值a=(5-2)/2+2=3;要将堆上的沙子堆到最多,那这5堆为:2,3,3,2,1.可以看到h之后增加再递减到h的堆数如果是奇数,那么就是有两个最大值,用等差数列求和公式来求用的沙袋的总数:可以分两部分,一部分是从h增加到最大值的和:首项为h,尾项为a,项数为a-h+1,和:(a+h)*(a-h+1)/2=(3+2)*(3-2+1)/2=5。一部分是最大值递减到1的和:首项为a,尾项为1,项数为a,和:(a+1)*a/2=(3+1)*3/2=6。沙袋总数为5+6=11>9.所以说明5堆是可以放下9袋沙的。

l=1,r=mid-1=4;l<r;继续二分。mid=(1+4)/2=2;mid=2=2,所以曲线是一直递减的,那么2堆要放的最多的沙袋数为:首项2,尾项1,项数2:(2+1)*2/2=3<9,所以说明2堆是不可能放下9袋沙的。

l=mid+1=3,r=4;l<r;继续二分。mid=(3+4)/2=3;mid=3>2,所以曲线一定是先增加后递减,(3-2)=1,所以说明增加到最大值再减少到2的堆数只有1堆。最大值a=(3-2)/2+2=2,所以这3堆为:2,2,1;沙袋总和就是分为两部分来做,一部分是从h增加到最大值的和:(2+2)*(2-2+1)/2=2。一部分是最大值递减到1的和:(2+1)*2/2=3。总和为5<9,说明3堆不可能放下9袋沙。

l=mid+1=4,r=4;l=r;继续二分。mid=(4+4)/2=4;mid=4>2,所以曲线一定是先增加后减少,(4-2)=2,所以说明增加到最大值再减少到2的堆数为2堆。偶数堆只有一个最大值。最大值为:(4-2)/2+2=3,所以这4堆为:2,3,2,1;沙袋总和就是分为两部分来做,一部分是从h增加到最大值的和:(3+2)*(3-2+1)/2=5。一部分是最大值递减到1的和:(3+1)*3/2=6。但是多加了一遍最大值,总和要减去一个最大值:11-3=9,说明4堆正好可以放下9袋沙。

l=4,r=mid-1=3;l>r;结束二分。

堆数为r+1=4堆。

猜你喜欢

转载自blog.csdn.net/SEVENY_/article/details/83187244