Gym 101194D Ice Cream Tower【二分+贪心】

很明显的一道二分答案,问题在于如何检验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);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42671946/article/details/88757292