2016百度实习机试题-乘法表

题目链接
题目描述:度度熊和爷爷在玩一个乘法表游戏。乘法表的第i行第j列位置的元素为i*j,并且乘法表下标编号从1开始,比如2 × 3乘法表为

1 2 3

2 4 6

爷爷十分聪明,对于n*m的乘法表,只要度度熊给出一个数k,爷爷就能立刻告诉度度熊乘法表中元素按照不减顺序排列之后,第k个元素是多少。你能重复这个游戏吗?

这道题刚开始没想太多,直接排序输出,后来看了大佬的思路才发现需要使用二分法进行查找,具体的思路就是起始的时候start = 0,ends = n*m,然后统计middle的值在其中为从小到大第几位,如果middle > 要求查找次数k,那么说明middle不符号条件,在middle+1与ends之间进行查找,如果middle <要求查找次数k,那么说明下一步应该在starts与middle-1之间进行查找,以此类推。
每次统计总次数的时候有一个小技巧,就是通过找寻前一个乘法表与后一个乘法表的关系进行查找,
比如第二行 i= 2 ,m = 4
即2 4 6 8 /2以后 就简化为 12 3 4 ( 是连续的一个数列)
i =3 的话 3 6 9 12 同理简化为1 2 3 4
这时候看出来没, 要把中间值 mid 与同行的数列比较,计算本行比其小或者相等的有几个的话,
做法是两边同除以 i 那么相当于m/i 与 1 2 3 4 比较 ,假设m = 8
原因:乘法表是呈倍数增长的,第一行为1 2 3 4,第二行为2 4 6 8为第一行的倍数,除以i之后
相等于把后面行的数字都转换到第一行进行比较
(第一行的数字乘以i = 第i行的数字)

#include <iostream>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <cstring>
#include <queue>
using  namespace  std;
int   main()
{
    long  long  int  n,m,k;
    cin>>n>>m>>k;
    long  long  int  start = 1;
    long  long  int  ends = n*m;
    //printf("ends = %lld\n",ends);
    long  long  int  middle = (start+ends)/2;
    while(start <= ends)
    {
        //printf("start = %lld,ends = %lld\n",
        //       start,ends);
        //printf("middle = %lld\n",middle);
        long  long  int   total = 0;
        for(long  long  int  i=1;i<=middle&&i<=n;i++)
        //共n行,从第middle+1行开始作乘法表就不可能找到比middle小的数字
        //最多进行n行
        {
            if(middle/i > m)
            {
                total +=m;
            }
            //middle/i为一行中比middle大的数字个数,如果数字个数超出一整行时
            //一整行全部取出
            else
            {
                total +=middle/i;
            }
            //否则只取出一整行中符合条件的数即可
        }
        //printf("total = %d\n",total);
        //每次比较的为middle,但是每次可查找的范围
        //为[start,ends]
        if(total >= k)
        {
            ends = middle-1;
            middle = (start+ends)/2;
        }
        //total比k大的情况说明下一次查找的范围为[starts,middle-1]
        else  if(total < k)
        {
            start = middle+1;
            middle = (start+ends)/2;
        }
        //total比k小的情况下说明下一次查找的范围为[middle+1,ends]
    }
    printf("%lld\n",start);
    //之前这里忘记使用lld的形式输出了,如果以%d的形式输出会有测试点不过。
    return  0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值