1. 程式人生 > >Problem D. Ice Cream Tower(2016 China-Final)【二分答案+貪心檢驗】

Problem D. Ice Cream Tower(2016 China-Final)【二分答案+貪心檢驗】

source:題目連結

題意:這是2016 ACM-ICPC China-Final的D題,一共有N個冰淇淋球,做一個冰淇淋需要K個球,並且由於穩定性,這K個球還必須滿足上下相鄰的下面比上面大至少兩倍。先給出N個球的質量,問最多能做出多少個冰淇淋?

思路:最開始以為就是簡單的貪心,但是發現貌似不對,後來在現場題目講解時才知道要用二分答案的方法,也就是對可以做多少個冰淇淋m做二分,每次檢驗是否能做出m個冰淇淋

      檢驗標準是:首先對B[]排序後將前m個取出來作為m個冰淇淋的頂端,也就是A[]的前m個=B[]的前m個,之後選A[i]時,貪心地去找滿足B[p]>2×A[i-m]的B[p]作為A[i],這樣p最多就只跑一遍(線性),如果能構成表示檢驗返回結果成功,反之返回結果失敗。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

LL b[300005],a[300005];
int t,T,n,k;


int judge(int m) //檢驗m個冰淇淋能否做出來
{
    for(int i=0;i<m;i++)
        a[i]=b[i];
    int p=m;
    for(int i=m;i<m*k;i++)
    {
        while(b[p]<a[i-m]*2 && p<n) p++;
        if(p==n) return 0;
        a[i]=b[p];
        p++;
    }
    return 1;
}

int Bisection(int l,int r)  //二分答案
{
    while(l<r)
    {
        int mid=(l+r+1)/2;
        if(judge(mid)) l=mid;
        else r=mid-1;
    }
    return l;
}

int main()
{
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++) scanf("%lld",&b[i]);
        sort(b,b+n);
        printf("Case #%d: %d\n",t,Bisection(0,n/k));
    }
    return 0;
}