当前位置:   article > 正文

第十二届蓝桥杯-杨辉三角形 详解_杨辉三角 考虑负数吗

杨辉三角 考虑负数吗

杨辉三角形

之前gitee把外链禁用了,导致图片显示不出来,现在已经解决了

第十二届蓝桥杯题目

题解

tips:以下说所的所有行和列是从0开始的,行是从左向右的,列是从上向下的!!!

首先我们需要知道的是,杨辉三角形其实就是组合数的一种形象化表示,第一行第一列代表的是 C 0 0 C_0^0 C00,而第二行第二列就是 C 1 1 C_1^1 C11……

那么我们学过组合数以后,很容易就知道第n+1行第m+1个元素(行列都是从0开始数)的值 C n m = n ! m ! ⋅ ( n − m ) ! C_n^m = \frac{n!}{m!·(n-m)!} Cnm=m!(nm)!n!

观察题目给出的元素,我们会发现杨辉三角形是一个中心对称的图形,那么我们可以猜出,题目让我们要找整数 N N N第一次出现的位置,那么我们可以确信的是, N N N第一次出现一定是在整个三角形的左半部分,所以我们可以把整个图形切成一半进行分析

如下:

image-20220319152626695

我们通过观察可以发现,对于第 i i i行,其最大值就在第 [ i 2 ] [\frac{i}{2}] [2i]列(这里地行和列都是从0开始数的)

然后我们手动拿计算器或者写程序枚举一下,发现 C 32 16 C_{32}^{16} C3216是小于 1 0 9 10^9 109的,而 C 34 17 C_{34}^{17} C3417是大于 1 0 9 10^9 109的,所以我们可以从第16列开始往前枚举。(why:其实对于第 i i i行,第 [ i 2 ] [\frac{i}{2}] [2i]列( C i [ i 2 ] C_i^{[\frac{i}{2}]} Ci[2i])确实是第 i i i行的最大值,但是对于第 [ i 2 ] [\frac{i}{2}] [2i]列,第 i i i行( C i [ i 2 ] C_i^{[\frac{i}{2}]} Ci[2i])其实是这一列的最小值,这个从上面的图应该可以看出来

这里先说一下,在对半分的杨辉三角形中,一行的数据是从左向右递增的,一列的数据是从上至下递增的,我们想要找到一个数 N N N的话,这个数第一次出现一定是在靠近右边列的地方,因为我们从最右边的列开始找,而最右边的列一定是这一列每个数所在行的最大值,如果找到了 N N N,那么前面行的所有数一定不会大于 N N N,那么他就是出现的第一个 N N N

所以这就是为什么要从右往左,从上向下查找的原因了。

我们发现列数并不多,但是行数很多,因为最坏的情况下,我们找到的第一个 N N N就是在第N行的第1列( C N 1 C_N^1 CN1),所以对于每一列,我们要从这一列的第一个元素 C i [ i 2 ] C_i^{[\frac{i}{2}]} Ci[2i]搜索到 C N [ i 2 ] C^{[\frac{i}{2}]}_N CN[2i],但是我们知道对于每一列的元素都是递增的,所以在进行列搜索的时候我们可以使用二分法来进行搜索

代码

package com.lanqiao;

import java.util.Scanner;

/**
 * @author 王宇哲
 * @date 2022/3/19 16:10
 */
public class 杨辉三角形 {


    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;
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/439348
推荐阅读
相关标签
  

闽ICP备14008679号