Gym 101194D / UVALive 7900 - Ice Cream Tower - [二分+贪心][2016 EC-Final Problem D]
题目链接:
http://codeforces.com/gym/101194/attachments
题意:
给出 $N$ 个冰淇淋球,第 $i$ 个冰淇淋球大小为 $B_i$,现在已知冰淇淋球堆叠起来可组成一个冰淇淋。
对于上下相邻的两个冰淇淋球,只有上面的那个大小不超过下面的那个的一般,才能堆叠起来。
现在已知 $K$ 个冰淇淋球可以组成一个冰淇淋,问给出的 $N$ 个冰淇淋球最多能组成多少个冰淇淋。
假的题解:
比赛的时候想的一个(假的)贪心思路:
从最大的冰淇淋球开始贪心,对于目前这个球,始终选择小于等于当前球体积的一半中体积最大的冰淇淋球。
进而可得这样一个用队列维护 $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); } }
转载请注明出处:https://dilthey.cnblogs.com/