Ice Cream Tower Gym - 101194D (二分答案、贪心检验)

题目:传送门

Solution:

二分答案和贪心检验就是这道题思路的核心,我来详细介绍一下其中的过程,直接算可以制造冰激凌的数量的话很困难,我感觉主要是有一个k的存在使得直接计算不好去想(我是不会的。。),但是检验的话就很好操作了,我们可以用二分的方法去一步一步缩小答案区间,最后就可以找到最大值了。

那么该如何检验呢?为了使得数量最大,我们每次肯定挑最小的那个放在顶层,然后找它的下面一层。举个例子,如果我们要验证是否能制作x个,我们就先挑出最小的x个来作为顶层,然后从x + 1开始遍历一遍依次放在这x个的下一层,直到最后。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 3 * 1e5 + 100;

ll cake[maxn], a[maxn];
int t, n, k;

bool check(int x)            //贪心检验
{
    if(!x)
        return true;
    int j = x + 1;
    for(int i = 1; i <= n; ++i)
         cake[i] = a[i];
    int i;
    for(i = x + 1; i <= n; ++ i)
    {
        while(i <= n && cake[j - x] * 2 > a[i])
            i++;
        if(i > n)
            return false;
        cake[j++] = a[i];
        if((j - 1) / x >= k)    return true;
    }
    if((j - 1) / x >= k)
        return true;
    else
        return false;
}

int Research(int l, int r)       //二分答案
{
    int res = -1;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) {
            res = mid;
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }
    return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    int s = 0;
    cin >> t;
    while(t --) {
        cin >> n >> k;
        for(int i = 1; i <= n; ++ i) {
            scanf("%lld", &a[i]);
        }
        sort(a + 1, a + 1 + n);
        int ans = Research(0, n / k);
        printf("Case #%d: ", ++ s);
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/84944529