Gym - 101194D (二分)

熊猫先生非常喜欢冰淇淋,尤其是冰淇淋塔。一个冰淇淋塔由K个冰淇淋球堆叠成一个塔。为了使塔稳定,下面的冰淇淋球至少要有它上面的两倍大。换句话说,如果冰淇淋球从上到下的尺寸是A0, A1, A2,···,AK 1,那么A0×2 ≤ A1, A1 × 2 ≤ A2,等等。
有一天,熊猫先生在街上走着,发现一家卖冰淇淋球的商店。冰淇淋球共有N个,大小分别为B0、B1、B2、··、BN−1。潘达先生想知道这些球最多能做出的冰淇淋塔数量。

Input

输入的第一行给出了测试用例的数量,接下来是T , T组测试用例。每个测试用例都以一个由2个整数组成的行开始,N是商店中冰淇淋球的数量,K是形成一个冰淇淋塔所需的冰淇淋球的数量。下一行包含N个整数,表示商店中各个冰淇淋球的大小。

Output

对于每个测试用例,输出一行包含“Case #x: y”,其中x是测试用例号(从1开始),y是冰淇淋塔的最大数量。

Limits

• 1 ≤ T ≤ 100.
• 1 ≤ N ≤ 3 × 105.
• 1 ≤ K ≤ 64.
• 1 ≤ Bi ≤ 1018.

Sample Input

3
4 2
1 2 3 4
6 3
1 1 2 2 4 4
6 3
1 1 2 2 3 4

Sample Output

Case #1: 2
Case #2: 2
Case #3: 1

题意:给你n个冰淇淋球,然后告诉你做一个冰淇淋需要k个冰淇淋球,要求下面的冰淇淋球的质量至少是上面冰激凌球质量的两倍,问你最多能做几个冰淇淋。

思路:这道题的话,题里告诉我们有n个冰淇淋球,然后每做一个冰淇凌需要k个冰淇凌球,所以最多可以做n/k个。然后我们有了区间,用二分的方法,设l=0,r=n/k,在这个区间里查找最大值。然后我们知道了用二分来做之后,我们应该检验一下查找的值,我们每做一个冰淇凌球,肯定会把最小的那一个冰淇凌球放在最上面,然后找它的下一层。所以假设我们可以做x个冰淇凌球,我们将最小的放在最上面,然后从第二个开始遍历一遍,找一下是否符合条件,然后检验一下即可。

AC代码:

#include <bits/stdc++.h>
typedef long long ll;
const int maxx=300010;
const int inf=0x3f3f3f3f;
using namespace std;
ll a[maxx],b[maxx];
int n,k;
int ef(int mid)
{
    int x=1;
    for(int i=1; i<=mid; i++)
        b[i]=a[x++];
    for(int i=2; i<=k; i++)
    {
        for(int j=1; j<=mid; j++)
        {
            while(a[x]<b[j]*2 && x<=n)
                x++;
            if(x>n)
                return 0;
            b[j]=a[x++];
        }
    }
    return 1;
}
int main()
{
    int t,cas=0;
    scanf("%d",&t);
    while(t--)
    {
        cas++;
        scanf("%d%d",&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;
        int ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(ef(mid))
            {
                l=mid+1;
                ans=mid;
            }
            else
                r=mid-1;
        }
        printf("Case #%d: %d\n",cas,ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值