题目大意
给出 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 x∗m≤∑bi,那么 x x x就可以作为答案。
二分答案先设定一个范围,由于范围没有那么大,那么我们设 l = 0 , r = s u m l=0,r=sum l=0,r=sum(实际上更严谨的是 l = n / m , r = s u m / m l=n/m,r=sum/m l=n/m,r=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;
}