戳我传送


题意:
n根木棍中截取k根长度一样的木棍,多余的木棍舍去。

思路:

先用最简单的方法从长度1开始一个一个枚举,直到达不到题目要求,这样的复杂度图片说明 (n^2),显然会超时。我们就可以选区间的中点,如果不行答案一定比这个小,如果可以我们继续试试大一点可不可以,一步步缩小区间,这是二分的思路。
以前属于完全套一个模板,现在才了解了一点二分:
因为我是把答案存在l上,所以如果当前mid可行,那么l=mid,否则r=mid-1,直到l==r。
l左区间,r右区间,mid要取l+r+1,刘大佬和吴大佬说是为了防止除数为0,这个我没想到,还有一点是使mid偏大一点,避免死循环,如果是mid=l+r,当r-l=1时,如果答案是刚好是l--字母,那么就会出现一直执行l=l的情况,也就是mid不变。
注意:因为可能存在无解的情况,如果把解空间设为[1,最大的木棍长度],那么第一个测试点就会wa,所以我猜第一个测试点的答案是0。


Code:


#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
void print(int x){
    if(x>=10) print(x/10);
    putchar(x%10+'0');
}
int a[200005],cnt,n,k;
bool check(int x) {
    int ans=0;
    for(int i=1;i<=n;++i) ans+=a[i]/x;
    if(ans<k)    return false;
    return true;
}
int main() {
    n=read(),k=read();
    for(int i=1;i<=n;++i) {
        a[i]=read();
        if(a[i]>cnt) cnt=a[i];
    }
    int l=0,r=cnt;
    while(l<r) {
        int mid=l+r+1>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    print(l),puts("");
}