zoukankan      html  css  js  c++  java
  • The 2016 ACM-ICPC Asia China-Final D. Ice Cream Tower 二分 + 贪心

    题目大意:

    对于给出的n个冰激凌球的大小,满足下面的球的大小是上一个的至少2倍,对于给出的k(由k的冰激凌球才能算作一个冰激凌塔),问n个冰激凌球可以最多堆出多少个高度为k的冰激凌塔

    题目分析:

    对于n个冰激凌球,显然我们得知可以堆出的高度为k的塔的数量在0~[n / k]之间,这里可以通过二分遍历每一种可能,初始时二分边界l==0,r==[n / k],每次取中间值mid=(l+r)/ 2,判断mid高度为k的塔能否堆出,如果可以则尝试mid为更大,否则则尝试mid为更小时,不断二分尝试mid是否可行,而对于每个mid,我们要写一个判断函数,来判断mid座高度为k的冰激凌塔能否堆出,这里用到了贪心的思维,我们先对n个冰激凌球的大小进行从小到大的排序,然后对于mid座塔我们只要创建一个一维数组,0~mid-1放置排完序的冰激凌球的前mid个(由于已经将冰激凌球排序,取出前mid个放入这个数组即可),然后循环k-1遍(因为高度初始已经为1,只要再判断k-1层的情况即可),从编号为mid开始依次选取冰激凌球(从小到大)与这个0~mid-1个位置进行比较,如果满足是它的至少两倍则更新0~mid-1位置的冰激凌球大小,否则继续往后找一个满足的冰激凌球去替换它,完成了一层之后则继续从0~mid-1开始(共k层),假如中途出现冰激凌球已经遍历到最后,但是还是k层冰激凌塔没有完成堆叠,则返回失败,否则在结束所有k层的每个判断后返回成功

    关于贪心的部分,由于数组是从小到大排序的,如果遇到一个位置不满足是它的至少两倍则将下标往后移动,前面的就被舍弃了(因为对后面的位置来说,它一定是比前面位置大的,指向该下标的冰激凌球大小如果不满足前者至少两倍,则不可能满足后者的至少两倍关系,而从小到大排序选择也是满足了最优的选择方案,先用小的试探,后用大的试探,小的一定在前面)

    代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cmath>
     4 using namespace std;
     5 
     6 const int M = 300005;
     7 long long ice[M];
     8 long long update[M];
     9 int n, k;
    10 
    11 bool judge(int x){        //x代表判断做x个塔是否可行 
    12     for(int i = 0; i < x; i++){
    13         update[i] = ice[i];
    14     }
    15     int cnt = x;
    16     for(int i = 1; i < k; i++){
    17         for(int j = 0; j < x; j++){
    18             while(update[j]*2 > ice[cnt] && cnt < n) cnt++;
    19             if(cnt == n) return false;
    20             update[j] = ice[cnt];
    21             cnt++;    
    22         }
    23     }
    24     return true;
    25 }
    26 
    27 int main(){
    28     int t;
    29     scanf("%d", &t);
    30     int cnt = 1;
    31     while(t--){
    32         scanf("%d%d", &n, &k);
    33         for(int i = 0; i < n; i++) scanf("%lld", &ice[i]);
    34         sort(ice, ice + n);
    35         int l = 0;
    36         int r = n/k;
    37         int ans = 0;
    38         while(l <= r){
    39             int m = (l+r)/2;
    40             if(judge(m)){
    41                 l = m+1;
    42                 ans = m;
    43             }else{
    44                 r = m-1;
    45             }
    46         }
    47         printf("Case #%d: %d
    ", cnt++, ans);
    48     } 
    49     return 0;
    50 }
  • 相关阅读:
    idea 使用jedis连接不上 redis解决办法
    EFCore 连接 MySql 间歇性报错:你的主机中的软件中止了一个已建立的连接
    初学Ansible(管理Window主机)
    茹炳晟-API自动化测试笔记
    Xpath路径
    kibana Dev Tools --常用命令
    kibana Dev Tools--修改语句示例
    kibana Dev Tools--增删改查语句
    记一次出名记录
    脚本:bat实现自动转换windows远程端口
  • 原文地址:https://www.cnblogs.com/YLTFY1998/p/11793275.html
Copyright © 2011-2022 走看看