很明显的一道二分答案,问题在于如何检验mid是否成立。
将数组进行排序,模拟每个塔的状态,双下标依次将a[i]加入塔内,记录即可。
详见注释。
#include "bits/stdc++.h"
using namespace std;
const int inf= 0x3f3f3f3f;
const int mod = 1e9+7;
long long a[300005];
long long n, k;
long long base[300005];//记录每个塔添加下一个冰淇淋的质量至少需要的数值
int Find(int m)
{
for (int i = 1; i <= m; ++i) {//优先将最小的m个作为塔顶,那么下一个加入的冰淇淋需要的质量就是a[i]*2
base[i]=a[i]*2;
}
long long num=m,cnt=1;
//num记录加入塔内的冰淇淋数量
//cnt用来模拟塔的下标,先对第一个塔进行操作,再第二个……到第m个,然后再循环回第一个。
for (int i = m+1; i <= n&&num<m*k; ++i) {
if(a[i]<base[cnt])continue;
base[cnt]=a[i]*2;
num++;
if(num==m*k)break;//因为我们是依次增加塔的高度,所以不存在有某一个塔的高度超过k的情况。
cnt++;
if(cnt>m)cnt=1;
}
return num>=m*k;
}
int main() {
int t;
int KASE = 1;
scanf("%d", &t);
while (t--) {
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
sort(a+1,a+n+1);
int l=0,r=n/k;//关于边界,n个做高为k的,那么最多为n/k。
int mid=(l+r)/2;
int ans=-1;
while(l<=r)//标准的二分模板
{
mid=(l+r)/2;
if (Find(mid))
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
printf("Case #%d: %d\n",KASE++,ans);
}
}