华华给月月准备礼物
Solution
根据题目大意,很快可以发现,如果我们枚举一个 ,可以在这个
情况下求到
根木棍,我们就希望能不能再求更大的
;
否则,可行解一定比当前ans更小。符合单调特性,采取二分的思路。
再说说我对二分的心得
二分大致可以分为两种思路,范围缩小让 逼近答案
while (l < r) {
ll mid = r + l >> 1;
if (a[mid]>=x) r = mid;
else l = mid + 1;
}范围缩小让 逼近答案
while (l < r) {
ll mid = r + l + 1 >> 1;
if (a[mid]<=x) l = mid;
else r = mid - 1;
}这两种区别在于求 的时候,第一种
不会取到
这个值;
第二种 不会取到
这个值。
根据不同题目选择合适的方法,去处理无解的情况。
总而言之, 正确写出这种二分的流程是:
- 通过分析具体问题,确定左右半段哪一个是可行区间, 以及mid 归属哪一半段。
- 根据分析结果,选择"r= mid, l = mid + 1, mid = (l + r)>>1" 和"l= mid, r = mid -1, mid= (l + r+ 1)>>1" 两个配套形式之一。
- 二分终止条件是l== r, 该值就是答案所在位置。
时间复杂度O(
)
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
ll a[N];
int n,k;
bool judge(ll x){
ll cnt=0;
for(int i=1;i<=n;++i) cnt+=a[i]/x;
return cnt>=k;
}
int main (){
scanf("%d %d",&n,&k);
for(int i = 1; i <= n; ++i)
scanf("%lld",&a[i]);
//二分求解,因为取不到0,并且我们让合法的答案保持在l中,选择第一种二分方法
ll l=0,r=1e9+7;
while(l<r){
ll mid=r+l+1>>1; //ll可以吧位运算写简单点,不然只有用r-(r-l)/2了
if(judge(mid)) l=mid;
else r=mid-1;
}
printf("%lld\n",l);
return 0;
}
京公网安备 11010502036488号