CF-985D.Sand Fortress(贪心、二分)

CF传送门

洛谷传送门


解题思路

总结一下,
其实只有两种情况:

  • k,k-1,k-2,k-3,k-4,k-5,……,1(k<=h)+ 一堆高度为[1,k]
  • h,h+1,……,h+x,h+x-1,h+x-2,……,1 + 一堆高度为[1,h+x]

贪心:k和x显然是越大越好。
于是我们可以二分k和x,可以得出答案。
注意的细节:
等差数列求和需要 \(h*(h+1)/2\) ,而 \(h<=1e18\) ,直接乘会炸long long。
所以我们可以一开始特判一下,因为\(n<=1e18\),所以若h>=1e9,一定是第一种情况,直接二分即可。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
long long n,h; 
bool check(long long x){
	if(x*(x+1)/2>=n) return true;
	return false;
}
bool check2(long long x){
	if((h+x)*(x-h+1)/2+x*(x+1)/2>=n) return 1;
	return 0; 
}
int main(){
	cin>>n>>h;
	if(h>=2e9||(h*(h+1)/2>=n-h)){
		long long l=1,r=min((long long)2e9,h),mid=(l+r)/2;
		while(l!=r){
			if(check(mid)) r=mid;
			else l=mid+1;
			mid=(l+r)/2;
		}
		if(l*(l+1)/2<n) l++;
		cout<<l<<endl;
		return 0;
	}
	long long l=h,r=2e9,mid=(l+r)/2;
	while(l!=r){
		if(check2(mid)) r=mid;
		else l=mid+1;
		mid=(l+r)/2;
	}
	long long ans=(l-h)+l;
	if((h+l)*(l-h+1)/2+l*(l+1)/2-l<n) ans++;
	cout<<ans<<endl;
    return 0;
}
posted @ 2021-05-16 21:57  尹昱钦  阅读(98)  评论(0编辑  收藏  举报