找规律 + 二分 - 杨辉三角形 - 第十二届蓝桥杯省赛第一场C++ B组

找规律 + 二分 - 杨辉三角形 - 第十二届蓝桥杯省赛第一场C++ B组

题意:

下面的图形是著名的杨辉三角形:
在这里插入图片描述
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:

1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …

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

输入格式

输入一个整数 N。

输出格式

输出一个整数代表答案。

数据范围

对于 20% 的评测用例,1 ≤ N ≤ 10;
对于所有评测用例,1 ≤ N ≤ 109

输入样例:

6

输出样例:

13

分析:
在这里插入图片描述

杨辉三角形的性质:

我们首先将三角形看作是一个三角矩阵。

性质1: 第 i 行 , 第 j 列 的 值 为 C i j ( i ≥ j ) 。 第i行,第j列的值为C_{i}^{j}(i\ge j)。 ijCij(ij)

性质2: 三 角 形 是 对 称 的 , 且 中 间 对 称 轴 上 的 数 字 为 C 2 i i , 其 中 i 是 它 所 在 的 行 号 。 三角形是对称的,且中间对称轴上的数字为C_{2i}^i,其中i是它所在的行号。 C2iii

如 , C 0 0 = 1 , C 2 1 = 2 , C 4 2 = 6 , C 6 3 = 20... \quad\qquad 如,C_0^0=1,C_2^1=2,C_4^2=6,C_6^3=20... C00=1C21=2C42=6C63=20...

性质3: 每 一 列 、 每 一 列 上 的 数 字 均 是 非 递 减 的 。 每一列、每一列上的数字均是非递减的。

本题中:

根据性质2,又因为我们要查找n第一次出现的位置,所以我们可以忽略三角形的右半部分(保留左半部分和中间)

得到的矩阵如下:
在这里插入图片描述
然后我们发现:

矩阵的每一行和每一列,都是递增的,而对称轴上的数,恰是矩阵中每一列的首个数字

所以,我们可以粗略的估计,当列号 j > 16 j > 16 j>16时, C 2 j j > 1 0 9 C_{2j}^{j}>10^9 C2jj>109,那么我们仅需考虑列号 j ∈ [ 0 , 16 ] j∈[0,16] j[016]的情况。

j j j 列数的取值为: C 2 j j 、 C 2 j + 1 j 、 . . . 、 C 2 j + k j , 其 中 k > 1 , C_{2j}^j、C_{2j+1}^j、...、C_{2j+k}^j,其中k>1, C2jjC2j+1j...C2j+kjk>1

此时,又根据性质3,我们可以在第j列上二分查找第一个大于等于 n n n 的数。

所以,我们可以从大到小枚举 j j j,在第 j j j 列上二分查找第一个大于等于 n n n的数,

若其与n相等,则输出其序号;否则,继续在 j − 1 j-1 j1 列上查找这个数。

序号的计算: 假设行号为 r r r,列号为 j j j,前 r − 1 r - 1 r1 行的数字的个数为 r ( r + 1 ) 2 \frac{r(r+1)}{2} 2r(r+1),则序号为 : r ( r + 1 ) 2 + j + 1 \frac{r(r+1)}{2}+j+1 2r(r+1)+j+1

从大到小枚举的原因: 因为我们要找第一个与 n n n 相等的数,即 C r j = n C_r^j=n Crj=n 的第一个数。

也就是满足 C r j = n C_r^j = n Crj=n 所有数中, r 最 小 的 一 个 数 r最小的一个数 r,要 r r r 尽量小,那么 j j j 就尽量大,所以从大到小枚举 j j j

二分的细节:

枚举第 j j j 列,我们二分它的行号 k k k k k k 的下界是 2 j 2j 2j, 上界必然不会超过n(因为第一列的第n行等于n)。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;

int n;

ll C(int a, int b)
{
    ll res = 1;
    for(ll up = a, down = 1; down <= b; up --, down ++)
    {
        res = res * up / down;
        if(res > n) return res;
    }
    return res;
}

bool check(int j)
{
    ll l = 2 * j, r = max((ll)n, l);
    while(l < r)
    {
        ll k = l + r >> 1;
        if(C(k, j) >= n) r = k;
        else l = k + 1;
    }
    
    if(C(r, j) != n) return false;
    
    cout<<(r + 1) * r / 2 + j + 1<<endl;
    
    return true;
}

int main()
{
    cin>>n;
    for(int j=16; ;j--)
        if(check(j))
            break;
        
    return 0;
}
  • 20
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 题目描述: 给定一个正整数n,输出杨辉三角形的前n。 输入格式: 输入一个正整数n。 输出格式: 输出杨辉三角形的前n,每数字之间用一个空格隔开。 样例输入: 5 样例输出: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 数据范围: 1≤n≤34 解题思路: 杨辉三角形的每一都可以看成是一个二项式系数,第i第j个数表示为C(i-1,j-1),可以通过递推公式C(i,j)=C(i-1,j-1)+C(i-1,j)来求得。 代码实现: ### 回答2: 杨辉三角形是一种数学规律,由中国古代数学家杨辉发现而得名,又称杨辉图。在数学中,杨辉三角形是一个数表,其中每个数是由上方两数相加而来。它起初只是用于排列合的计算,但它的性质也使它成为了许多数学领域的重要工具。 该题中要求实现杨辉三角形的生成,并输出第 n 第 k 项的值。这题使用的是合数的性质:杨辉三角形的第 n 第 k 个数就是合数 $C_{n-1}^{k-1}$。 因此,我们可以很容易地实现对杨辉三角形的生成,只需要使用两重循环即可,复杂度为 $O(n^2)$。而输出第 n 第 k 个数的值则只需要计算合数 $C_{n-1}^{k-1}$ 即可,这可以使用递推公式求数合数来完成,复杂度为 $O(n)$,因此总时间复杂度为 $O(n^2)$。 此外,在实现过程中,还需要注意一些细节,如数下标的问题,以及输入输出格式的要求等。 总之,这道题要求我们掌握杨辉三角形的生成和合数的计算方法,以及一些基本的编程技巧,能够灵活运用循环和递推等方法解决问题。掌握这些知识和技巧不仅可以帮助我们解决这道题,也能帮助我们解决其他相关的数学和编程问题。 ### 回答3: 这道题为杨辉三角形,要求输出p杨辉三角形的前n项之和。杨辉三角形是中学数学中的常见概念,在数学上有重要应用。开始时,我们先输入测试数据,其中包括P、n和杨辉三角形。然后,我们就要开始对数据进处理。首先,我们要创建一个二维数来存储杨辉三角形中的每个元素,并对其进初始化。 其次,我们需要使用嵌套的for循环来填充数。外层循环用来遍历杨辉三角形的每一,内层循环则用来填充每一的元素。填充的方法是通过将上一相邻元素相加的方式来得到当前的元素。每第一个和最后一个元素都为1。在填充完杨辉三角形后,我们通过for循环来输出前n项的和,最后将结果返回。 需要注意的是,在处理数据时要注意异常情况,例如P、n的取值范围以及杨辉三角形的格式是否正确等。 总体来说,这道题需要我们掌握二维数和嵌套循环的使用方法,并要注意输入输出的格式。可以通过多练习类似的题目来加深对知识点的理解和熟练度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值