2019 ICPC 沈阳区域赛 - L Flowers(二分答案)

题目链接


题目大意

给出 n n n种花,现在每一种都有 a i a_i ai个,要扎成花束,该花束满足有 m m m多花并且每种花只能有 1 1 1朵,问最多能扎几束花?

解题思路

先假设最多扎 x x x束花,因为每种花在每一束最多有一朵,那么需要每一种花的数量为 b i = m i n a i , x b_i = min { a_i , x } bi=minai,x,由于每种花的数量可能大于 x x x也可能小于 x x x,那么即使数量多于 x x x也再扎不了一束了,因为假设的是当前最大的 x x x。如果 x x x能满足 x ∗ m ≤ ∑ b i x*m \leq \sum b_i xmbi,那么 x x x就可以作为答案。

二分答案先设定一个范围,由于范围没有那么大,那么我们设 l = 0 , r = s u m l=0,r=sum l=0r=sum(实际上更严谨的是 l = n / m , r = s u m / m l=n/m,r=sum/m l=n/mr=sum/m),对区间二分答案即可。可以证明,如果当前 x x x满足条件后,那么右边可能仍存在一个更大的 x x x满足条件,因此满足条件左边界右移,否则右边界左移。

二分答案有很多写法,有时候数据范围很大时,直接二分一百次,一定能找到答案,本题一般的二分即可

写法一:

while(l<=r){
	mid=(l+r)>>1;
	if(check(mid)){
		ans=mid;
		l=mid+1;
	}else r=mid-1;
}

写法二:

while(l<r){
	mid=(l+r)>>1;
	if(check(mid+1)){
		l=mid+1;
		ans=mid;
	}else r=mid;
}

写法三:

for(int i=1;i<=100;i++){
	mid=(l+r)>>1;
	if(check(mid)){
		ans=mid;
		l=mid+1;
	else r=mid-1;
}

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
#define lowbit(x) (x&(-x))
const int N=3e5+10;
ll a[N],d[N];
int t,n,m;
ll ans;

bool check(ll x){
    ll res;
    int r=upper_bound(a+1,a+1+n,x)-a;   //找大于x的第一个元素
    res=(d[r-1]+(n-r+1)*x)/m;  //当数组所有元素都大于x时,返回的是1
    if(x<=res) return true;
    else return false;
}

void solve(ll sum){
    ll l=n/m,r=sum/m,mid;
    ans=l;
    /*while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }else r=mid-1;
    }*/
    for(int i=1;i<=100;i++){
        mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }else r=mid-1;
    }
}

int main(){
    scanf("%d",&t);
    while(t--){
        ll res=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            res+=a[i];
        }
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++){
            d[i]=d[i-1]+a[i];
        }
        solve(res);
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值