蓝桥杯题解——杨辉三角形

653 阅读2分钟

蓝桥杯题解——杨辉三角形

题目描述

下面的图形是著名的杨辉三角形:

image

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, \cdots1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯

给定一个正整数 NN,请你输出数列中第一次出现 NN 是在第几个数?

输入描述

输入一个整数 NN。

输出描述

输出一个整数代表答案。

输入输出样例

示例 1

输入

6

输出

13

评测用例规模与约定

对于 20%20​​ 的评测用例,1\leq N\leq 101≤N≤10​; 对于所有评测用例,1\leq N\leq 10000000001≤N≤1000000000。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M
public class Main {
 static int N;

    /**
     * 求组合数<br/>
     * C_n^m = [n*(n-1)*...*(n-m+1)] / [1 * 2 * ... * m]
     * @param m 选几个球?
     * @param n 从几个球中选?
     * @return 选择方案数
     */
    static long C(int m, int n){
        long res = 1;

        for(int i = n, j=1; j<=m;j++,i--){

            res *= i;
            res /= j;

            //如过算出来已经大于N了,继续算不仅没意义,而且会越界,出现负数,扰乱判断
            if(res > N){
                return res;
            }

        }

        return res;

    }

    /**
     * 在这一列中搜索N第一次出现的位置
     * @param column 当前搜索的列数
     * @return N第一次出现的位置,没出现就返回-1
     */
    static long searchFirstAppearByColumn(int column){

        // 这一列的第一个元素是在2column处
        int left = 2 * column;

        //搜索到第N行就可以停止了
        //这里注意一下,如果搜索1,那么在第1列的时候,左边界是2,N是1
        //如果右边界是N的话最后搜索到的就是第1行第1列的1,那么输出结果就会变成3,这明显是不成立的
        //所以我们要保证开始搜索时左边界要小于等于右边界
        int right = Math.max(N,left);

        int mid = (left + right) >> 1;

        //暂存计算结果
        long tmpResult;

        //二分搜索
        while(left <= right){

            //位运算,相当于浅浅加个速,但是加了不少逼格
            mid  = (left + right) >> 1;

            tmpResult = C(column,mid);

            //找到了就退出循环
            if(tmpResult == N){

                break;
            }
            if(tmpResult > N){
                //如果找的数过大了,就从左区间继续找,为了避免死循环,右边界要减1
                right = mid-1;
            }else{

                //为了避免死循环,左边界要加1
                left = mid+1;
            }

        }


        //如果找到了的值确实是N
        if(C(column, mid) == N){

            //right是行号
            return (long) (mid) *(mid +1)/2 + column + 1;

        }

        return -1;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        N = scanner.nextInt();

        long ans;

        for(int i = 16 ;i >= 0;i--){

            //赋值完来个比较,不是-1就是找到了,返回其位置
            if((ans = searchFirstAppearByColumn(i)) != -1){

                System.out.println(ans);

                break;
            }
        }
    }
}

image.png