1. 程式人生 > >101194 D Ice Cream Tower 二分 + 貪心判斷

101194 D Ice Cream Tower 二分 + 貪心判斷

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;
}