3418 杨辉三角形(找规律 + 二分)

1. 问题描述:

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

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:1,1, 1, 1, 2, 1, 1, 3, 3,1, 1, 4, 6, 4, 1, ...给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?

输入格式

输入一个整数 N。

输出格式

输出一个整数代表答案。

数据范围

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

输入样例:

6

输出样例:

13
来源:https://www.acwing.com/problem/content/3421/

2. 思路分析:

每一个杨辉三角上的数字都对应一个组合数Cr c,其中r和c分别是对应的行数与列数(行数与列数从0开始),因为找的是第一次出现的数字,可以发现左右两部分的数字是对称的,所以只需要看左半部分的数字即可,每一行最大的数字为Cr r/2,最大的数字也是第一次出现的数字,比如第8行出现最大的数字为C7 3,第9行出现的最大的数字为C8 4,我们可以大概估算一下数据规模,因为N最大是10 ^ 9,而C32 16 = 601080390 > 10 ^ 9,所以杨辉三角最多有32行,而且从每一行从左到右,从上到下都是递增的,所以可以使用二分查找,从k = 16行开始寻找,Cr k中r >= 2k,r = max(2k,n),n为当前要寻找的数字,当前最小的数字是C2k k,第一次出现的数字一定满足Cr c中c <= r / 2,例如要找C10 6,其中当k = 6的时候二分查找的数字最小的数字为C12 6一定大于n,只有当k = 4的时候才会最终找到对应的r = 10,C10 6 = C10 4. 这个数字也是第一次出现的数字,二分找到的(r,k)就是n第一次的位置,前面总共有r行,左边有k + 1个数字,所以当前的数字n第一次出现是第r * (r + 1) / 2 +  k + 1个数字。

3. 代码如下:

class Solution:
    # 求解组合数Ca b, 使用定义来求解
    def C(self, a: int, b: int, n: int):
        res = 1
        i, j = a, 1
        while j <= b:
            res = res * i // j
            # 超过了n说明直接返回False就可以了, 肯定是大于n的
            if res > n: return res
            i -= 1
            j += 1
        return res
    
    # 找到当前最小的r判断是否满足条件, r >= 2k
    def check(self, k: int, n: int):
        l = 2 * k
        r = max(n, l)
        while l < r:
            mid = l + r >> 1
            if self.C(mid, k, n) >= n:
                r = mid
            else:
                l = mid + 1
        if self.C(r, k, n) != n: return False
        # 找到了这个数字
        print(r * (r + 1) // 2 + k + 1)
        return True

    def process(self):
        n = int(input())
        # 从16开始枚举
        for i in range(16, -1, -1):
            if self.check(i, n): break


if __name__ == "__main__":
    Solution().process()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值