1.题意:给你n个冰激凌球的体积,告诉你k个球能合成一个冰激凌,合成条件是放在第一个球下面的球体积要大于等于他的两倍。问你最多能合成多少个。
2.分析:
最少能合成0个,最多能合成n/k个。存在单调性上下界,于是我们二分合成数量。
怎么判断mid个能否合成呢?我们知道最上面的球体积越小,可选择的情况越多,合成得最多!所以既然要合成mid个,我们就选前mid个作为mid个冰激凌的顶部,以此类推选下一个底,看看能否合成mid个即可。
3.代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 300000 + 100;
LL num[maxn],check[maxn];
int n,k;
bool judge(int u){
int i;
for(i = 0;i<u;i++)check[i] = num[i];//前mid个作为顶球
for(int p = 1;p<k;p++){//每一个要选k个合成
for(int j = 0;j<u;j++){//进行u次
if(i>=n)return false;
int pos = lower_bound(num+i,num+n,check[j]*2) - num;
if(pos>=n){
return false;
}
check[j] = num[pos];
i = pos+1;
}
}
return true;
}
int main()
{
int T;
scanf("%d",&T);
int t = 0;
while(T--){
t++;
scanf("%d%d",&n,&k);
for(int i = 0;i<n;i++){
scanf("%lld",&num[i]);
}
if(k==1){
printf("Case #%d: %d\n",t,n);
continue;
}
sort(num,num+n);
int l = 0,r = n/k;
int ans = 0;
while(l<=r){//二分
int mid = (l + r)/2;
if(judge(mid)){//判断mid个能否合成
ans = mid;
l = mid+1;
}
else r = mid-1;
}
printf("Case #%d: %d\n",t,ans);
}
return 0;
}