Gym 101194D / UVALive 7900 - Ice Cream Tower - [二分+贪心][2016 EC-Final Problem D]

题目连接:php

http://codeforces.com/gym/101194/attachmentsc++

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5922spa

 

题意:code

给出 $N$ 个冰淇淋球,第 $i$ 个冰淇淋球大小为 $B_i$,如今已知冰淇淋球堆叠起来可组成一个冰淇淋。blog

对于上下相邻的两个冰淇淋球,只有上面的那个大小不超过下面的那个的通常,才能堆叠起来。队列

如今已知 $K$ 个冰淇淋球能够组成一个冰淇淋,问给出的 $N$ 个冰淇淋球最多能组成多少个冰淇淋。ci

 

假的题解:get

比赛的时候想的一个(假的)贪心思路:it

  从最大的冰淇淋球开始贪心,对于目前这个球,始终选择小于等于当前球体积的一半中体积最大的冰淇淋球。io

进而可得这样一个用队列维护 $O(N)$ 的作法:

  从大到小枚举冰淇淋球,用一个队列维护:目前产生的冰淇淋的最上端的那个冰淇淋球,以及该冰淇淋包含的冰淇淋球数目。

  枚举到当前这个球 $B_i$,与队首冰淇淋进行比较,若能够放到这个冰淇淋上,就放上去产生一个新的冰淇淋,出队队首元素,入队一个新冰淇淋;不然就做为一个新的冰淇淋入队。

 

代码(AC on UVALive 7900, WA on Gym 101194D):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
const int maxn=3e5+10;

int n,k;
ll b[maxn];
queue<pli> Q;

int main()
{
    int T;
    cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
        sort(b+1,b+n+1);
        int ans=0;
        while(!Q.empty()) Q.pop();
        for(int i=n;i>=1;i--)
        {
            if(Q.empty())
            {
                Q.push(make_pair(b[i],1));
                continue;
            }
            pli now=Q.front();
            if(b[i]<=(now.first>>1))
            {
                Q.pop();
                if(now.second+1>=k) ans++;
                else Q.push(make_pair(b[i],now.second+1));
            }
            else Q.push(make_pair(b[i],1));
        }
        printf("Case #%d: %d\n",kase,ans);
    }
}

 

 

真的题解:

若要求作 $cnt$ 个冰淇淋,那么确定先取最小的 $cnt$ 个冰淇淋球做为顶,而后一点点往先后推判断是否真的能作出 $cnt$ 个球。

那么,就能够二分答案,最少 $0$ 个冰淇淋,最多 $\left \lfloor \frac{N}{K} \right \rfloor$ 个冰淇淋。

时间复杂度 $O(N \log \left \lfloor \frac{N}{K} \right \rfloor)$

 

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli;
const int maxn=3e5+10;

int n,k;
ll b[maxn];
queue<pli> Q;
inline bool judge(int cnt)
{
    for(int i=1;i<=cnt;i++) Q.push(make_pair(b[i],1));
    for(int i=cnt+1;i<=n;i++)
    {
        pli now=Q.front();
        if(b[i]>=(now.first<<1))
        {
            Q.pop();
            Q.push(make_pair(b[i],now.second+1));
        }
    }
    int res=0;
    while(!Q.empty())
    {
        res+=(Q.front().second>=k);
        Q.pop();
    }
    return res>=cnt;
}

int main()
{
    int T;
    cin>>T;
    for(int kase=1;kase<=T;kase++)
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
        sort(b+1,b+n+1);
        int l=0, r=n/k;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(judge(mid)) l=mid;
            else r=mid-1;
        }
        printf("Case #%d: %d\n",kase,l);
    }
}
相关文章
相关标签/搜索