Recently Jack becomes much more romantic. He would like to prepare several bunches of flowers.Each bunch of flowers must have exactly M flowers. As Jack does not want to be boring, he hopes that flowers in the same bunch are all different species. Now there are N species of flowers in the flower shop, and the number of the i-th species of flower is ai. Now Jack would like to know how many bunches of flowers he can prepare at most.(Flowers are used to propose.)
Input
The first line contains an integer T (1≤T≤10) — the number of test cases.In the first line of each test case, there are two integers N, M (1≤N,M≤300000) — the number of flowers’ species and the number of flowers in a bunch.In the second line of each test case, there are N integers — the i-th integer indicates ai
(1≤ai≤109), the number of i-th species’ flowers.
Output
For each test case, output one integer in one line — the answer of the corresponding test case.
Sample Input
1
5 3
1 1 1 2 1
Sample Output
2
1.题目大意:给出n种花,现在每一种都有ai个,要扎成花束,该花束满足有m多花并且每种花只能有1朵,问最多能扎到几束花
2.比赛时没能写出来,上一次写二分答案是在2019暑假,如今忘的差不多了,主要是一直在学习新的东西,没时间对每个知识点刷题巩固,导致以前学过的不太牢,但也没办法。请教了学长,但是知道怎么做之后,花了我三天去改错,之前求前缀和一直用的树状数组,但是不知道为什么一直WA,检查了n遍没发现错误。今天实在没办法了,写了数组保存前缀和,然后就过了
3.言归正传,正解:先假设最多扎x束花,因为每种花在每一束最多有一朵,那么需要每一种花的数量为bi = min { ai , x },由于每种花的数量可能大于x也可能小于x,那么即使数量多于x也再扎不了一束了,因为假设的是当前最大的x。如果x能满足x*m<=Σbi,那么x就可以作为答案。因为我们要二分答案,因此先设定一个范围,由于范围没有那么大,那么我们设l=0,r=sum(实际上更严谨的是l=n/m,r=sum/m),对区间二分答案即可。可以证明,如果当前x满足条件后,那么右边可能仍存在一个更大的x满足条件,因此满足条件左边界右移,否则右边界左移
4.二分答案有很多写法,有时候数据范围很大时,直接二分一百次,一定能找到答案,但是本题一般的二分即可
写法一:
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;
}else r=mid;
}
ans=l;
写法三:
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的第一个元素
if(r!=0) res=(d[r-1]+(n-r+1)*x)/m; //当数组所有元素都小于x时,返回的是0,要特判
else res=n*x/m;
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;
}