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;
}