• 二分算法题目训练(一)——Shell Pyramid详解


    HDU2446——Shell Pyramid 详解

    • Shell Pyramid
    • 题目描述(Google 翻译的)
      在17世纪,由于雷鸣般的喧嚣,浓烟和炽热的火焰,海上的战斗与现代战争一样。但那时,大炮非常简单。它就像一个铁缸,其后端密封,前端打开。它的后端有一个小孔,用来安装保险丝。战舰上的大炮被放在有四个轮子的小型车辆上,炮弹是铁球,里面装着火药。

      当时,据说有一位聪明的船长,他也是一位数学家的业余爱好者。他喜欢把他遇到的所有东西都连接到数学上。在每次战斗之前,他经常命令士兵将炮弹放在甲板上并使这些炮弹形成炮弹金字塔。

      现在让我们假设一个壳金字塔有四层,每层都会有一系列序数。它们如下图所示:
      这里写图片描述

      在该图中,它们分别是从左到右的第一层,第二层,第三层和第四层。

      在第一层中,只有1个壳,其序数为1.在第二层中,有3个壳,它们的序数为1,2和3.在第三层中,有6个壳,它们的序数分别为1,2,3,4,5和6.在第四层中,有10个壳,它们的序数在上图中显示。

      整个贝壳金字塔也有序列号。例如,第二层中第三个外壳的序列号为4,第三层中第五个外壳的序列号为9,第四层中第九个外壳的序列号为19。

      还有一个相互关联的问题:如果给出一个序列号s,那么我们可以计算出第s个shell是在什么层,什么行和什么列。假设层数是i,行数是j而列数是k,因此,如果s = 19,则i = 4,j = 4并且k = 3。

      现在让我们继续讲述船长的故事。
      一场战斗即将开始。船长给每个大炮分配了相同数量的炮弹。炮弹堆放在甲板上,由炮弹形成相同的炮弹金字塔。当敌人的战舰靠近时,船长命令同时开火。然后听到了雷鸣般的声音。船长仔细听了,然后他就知道有多少炮弹被使用了,剩下多少炮弹了。

      在战斗结束时,船长赢了。在休息期间,他向下属询问了一个问题:对于壳金字塔,如果给出序列号s,你如何计算层数i,行号j和列号k?

    • 输入
      首先输入一个数字n,再进行n个案例。对于每种情况,都有一个足够大的壳金字塔,给出一个整数,这个整数是序列号s(s <2 ^ 63)。有几个测试用例。输入由文件末尾终止。
    • 输出
      对于每种情况,输出相应的层编号i,行编号j和列编号k。
    • 样例输入
      2
      19
      75822050528572544
    • 样例输出
      4 4 3
      769099 111570 11179
    • 思路分析
      • 首先通过二分先确定给出的数字是哪个金字塔,要找到是哪个金字塔,就需要知道给定序号代表的意思,序号是宏观的炮弹下标,因此它必然代表之前已经出现的所有炮弹,要找到它属于第几个金字塔,就需要一个数组来存储对于金字塔序号 i,它和它之前所有的金字塔会产生多少炮弹。
      • 再通过二分确定是属于这个金字塔的哪一层。要找到它是哪一层,就需要知道这个金字塔有多少个炮弹,因此还需要一个数组来存储对于金字塔序号 i,它自己会产生多少炮弹。
    • 设计思路
      1. 对于第 i 个金字塔,它所包含的炮弹数都是第 i-1 个金字塔所包含的炮弹数加上 i,比如第二个金字塔有 3 个炮弹,那么第三个就有 3+3 个炮弹,因此得到非递减序列 a[i] = a[i-1] + i
      2. 对于第 i 个金字塔,所有的炮弹数目为 i-1 个金字塔所包含炮弹数目与自己含有炮弹之和,因此得到非递减序列 sum[i] = sum[i-1] + a[i]
      3. 接下来只需要两次二分找出结果,找到金字塔序号 p 后,减去sum[p-1],就会得到所在金字塔中第多少个炮弹,找到行号 row 后,减去a[row-1],就是列号。
    #include <iostream>
    #include <cstdio>
    #include<cmath>
    
    #define Maxn 1000000
    
    using namespace std;
    
    typedef long long int LL;
    
    LL a[Maxn];
    LL sum[Maxn];
    
    LL find_index(LL *array,LL size,LL key);
    
    int main()
    {
        int i;
        a[1] = 1;
        for(i=2; i<Maxn; i++)
        {
            a[i] = a[i-1]+i;
        }
        sum[1] = 1;
        for(i=2; i<Maxn; i++)
        {
            sum[i] = sum[i-1]+a[i];
        }
        int t;
        scanf("%d",&t);
        while(t--)
        {
            LL num;
            cin >> num;
            LL p = find_index(sum,Maxn,num);
            num -= sum[p-1];
            LL row = find_index(a,Maxn,num);
            LL col = num-a[row-1];
            cout<<p<<" "<<row<<" "<<col<<endl;
        }
        return 0;
    }
    LL find_index(LL *array,LL size,LL key)
    {
        int first = 0, last = size-1;
        int middle, pos=0;
    
        while(first < last)
        {
            middle = (first+last)/2;
            if(array[middle] < key)
            {
                first = middle + 1;
                pos = first;
            }
            else
            {
                last = middle;
                pos = last;
            }
        }
        return pos;
    }
    • 对于非递减序列,可以使用 STL 中的 lower_bound()
    #include <iostream>
    #include <cstdio>
    #include<cmath>
    
    #define Maxn 1000000
    
    using namespace std;
    
    typedef long long int LL;
    
    LL a[Maxn];
    LL sum[Maxn];
    
    int main()
    {
        int i;
        a[1] = 1;
        for(i=2;i<Maxn;i++)
        {
            a[i] = a[i-1]+i;
        }
        sum[1] = 1;
        for(i=2;i<Maxn;i++)
        {
            sum[i] = sum[i-1]+a[i];
        }
        int t;
        scanf("%d",&t);
        while(t--)
        {
            LL num;
            cin >> num;
            LL p = lower_bound(sum,sum+Maxn,num)-sum;
            num -= sum[p-1];
            LL row = lower_bound(a,a+Maxn,num)-a;
            LL col = num-a[row-1];
            cout<<p<<" "<<row<<" "<<col<<endl;
        }
        return 0;
    }
  • 相关阅读:
    LVS + Keepalived + Nginx基于DR模式构建高可用方案
    基于SpringBoot从零构建博客网站
    基于SpringBoot从零构建博客网站
    基于SpringBoot从零构建博客网站
    基于SpringBoot从零构建博客网站
    精通Java中的volatile关键字
    基于Mycat实现读写分离
    整体二分
    pb_ds模板
    树状数组上二分(logn求第k小)
  • 原文地址:https://www.cnblogs.com/NikkiNikita/p/9450725.html
Copyright © 2020-2023  润新知