【蓝桥杯】杨辉三角形【第十二届】【省赛】

在这里插入图片描述

性质

规定1≤j≤i

  • 第i行共i个数;
  • 第i行j列的值为C(i-1,j-1);
  • 第i行的最大值是C(i-1,(i-1)/2)
  • 第二列是一个d=1的等差数列,所以一定存在N,且一定是最后出现的N。

题解1:DP

分析

  用dp做不需要C(n,m)的计算,但需要一个数组保存数据,经过优化后可以是一个一维数组。
  考虑到:第三列也很容易得到递推公式,第i行第三列的值为ai3 =(i-2)(i-1)/2 ,i≥2 。
  我们可以计算出ai3第一次大于10亿的i=44723 。

for(long i =3L;;++i){
	if((i-1)*(i-2)>2000000000L) {
    	System.out.println(i);
        break;
    }
}

  此时,我们只需要对前44722行进行dp计算,即可找到N。考虑到杨辉三角的递增性质,如果找不到,N一定N+1行的第二个数。
  dp优化后,我们只需要一个大小至少为44723的一维long数组。

代码实现

import java.util.Scanner;

public class Main {
    static long[] num = new long[44723];
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N = scan.nextLong();
        if(N == 1) {
            System.out.println(1);
            return;
        }
        num[1] = 1L;
        //dp计算
        for(int i =2;i<=44722;++i){
            for(int j =i;j>=1;--j){
                num[j] += num[j-1];
                if(num[j] == N){
                    /*这里容易出错!
                    * 因为是下标从大到小的dp,杨辉三角是对称的,先满足的是对称轴右边的数
                    * 这里结果res的计算需要做一下对称处理,不是i*(i-1)/2 +j
                    * 实际上是第i行的第i-j+1个数首先满足相等条件*/
                    long res = (((long) i *((long) i -1))>>1)+i-j+1;
                    System.out.println(res);
                    return;
                }
            }
        }
        //此时,N一定是 第N+1行的第二个数
        long res = ((N*(N+1))>>1)+2;
        System.out.println(res);
    }
}

提交结果

在这里插入图片描述

参考链接

蓝桥杯 PREV-284 杨辉三角形【第十二届】【省赛】

题解2

分析

在这里插入图片描述
  如图,剔除1后,取奇数行的最大值作为每一“列”的首元素。
结合杨辉三角的性质,数N如果出现在多“列”中,在较大“列”中N在杨辉三角中的位置靠前。所以我们要从大到小遍历“列”。

    static long N;
    static long C(long n,long m){
        long res = 1L;
        m = Math.min(m,n-m);//C(n,m)= C(n,n-m)
        for(int i=0;i<m;++i){
            //初等数论:任意n个连续整数之积一定是n的倍数
            res *= n-i;
            res /= i+1;
            /*在大组合数的计算中,一定会溢出爆long
             * 在本题中,我们要找等于N的数,所以一旦res超过N,再继续计算已经没用意义
             * 此时,返回任意大于N的数即可*/
            if(res>N)return res;
        }
        return res;
    }
计算组合数函数
N = 1000000000L;//给一个较大值或者注释if(res>N)return res;语句,否则下面的计算组合数将会出错
for(int i =1;;++i){
    //第i行的最大值是C(i-1,(i-1)/2)
    if(C(i-1,(i-1)>>1) > 1000000000) {
        System.out.println(i);
        break;
    }
}
计算最大列
  计算结果是34,在剔除1后,还剩16"列",其中第16"列"只存在一个合法元素,即杨辉三角中第33行的最大值C(32,16)= 601080390L。一开始做if判断即可不遍历第16"列",从第15"列"开始,嫌麻烦也可以直接从第16"列"开始遍历。

代码实现

import java.util.Scanner;

public class Main {
    /**
     * 初等数论:任意n个连续整数之积一定是n的倍数
     */
    static long N;
    static long C(long n,long m){
        long res = 1L;
        m = Math.min(m,n-m);//C(n,m)= C(n,n-m)
        for(int i=0;i<m;++i){
            res *= n-i;
            res /= i+1;
            /*在大组合数的计算中,一定会溢出爆long
             * 在本题中,我们要找等于N的数,所以一旦res超过N,再继续计算已经没用意义
             * 此时,返回任意大于N的数即可*/
            if(res>N)return res;
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        N = scan.nextLong();
        if(N == 1) {
            System.out.println(1);
            return;
        }
        if(N == 601080390L) {//第16"列"只有一个元素
            System.out.println(32*33/2 +17);
            return;
        }
        //对剩下的15"列"进行二分查找
        //第i"列"的所有数是杨辉三角中每一行n的第i+1个数,其值为C(n+1,i);
        for(int i =15;i>=1;--i){
            //第i"列"的起点位于杨辉三角的第2i+1行,因次左边界l取2i
            //第一列的值是d=1的等差数列,至少在r=N处,会满足等于N的条件,所以右边界取N
            long l = i<<1,r=N;
            while(l<r){
                long mid = (l+r)>>1;
                //找最先出现的
                if(C(mid,i)>=N)r = mid;
                else l = mid+1;
            }
            if(C(l,i)==N){
                //该点是杨辉三角中第l+1行的 第i+1个数
                long res = ((l*(l+1))>>1)+i+1;
                System.out.println(res);
                return;
            }
        }
    }
}

提交结果

在这里插入图片描述

参考链接

蓝桥杯2021年第十二届真题第一场-杨辉三角形

补充

在竞赛过程中一般不会去进行额外计算,所以另一种思路是从小"列"到大“列”扫描,大“列”的上确界给一个较大值(本题中大于等于16即可),然后取这些“列”中N位置的最小值,即为所求。
参考:第十二届蓝桥杯B组省赛杨辉三角形题解

备注

  本文整理的思路都是答题过程中可以想到的,肯定存在更优的解决思路,但不做讨论。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值