Acwing3418. 杨辉三角形(相对难思考一点,各种小细节比较多,当然也可能是我太菜)

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

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:

1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, ...

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

输入格式

输入一个整数 N。

输出格式

输出一个整数代表答案。

数据范围

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

输入样例:

6

输出样例:

13

 参考了一些别人的代码

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

using namespace std;

typedef long long LL;

int n;
/*
    组合数和杨辉三角:第i行第j列的数都是组合数C(i, j) (i,j从0开始)
        C(n, 1) = n --> 对应从左向右看斜着的第二列! ---> 一定有解
    由于杨辉三角左右对称(C(a, b) == C(a, a-b)),又由于找第一次出现,因此一定在左边,右边可以直接删掉!

            1  ---> C(0, 0)
          1 
        1   2  ---> C(2, 1)
      1   3                             ---> C(2n, n)
    1   4   6  ---> C(4, 2)
  1   5   10
1   6   15  20 ---> C(6, 3)

    n最大1e9,C(34, 17) > 1e9, C(32, 16) < 1e9,因此只要枚举前16个斜行即可!


    性质:
        1. 每一斜行从上到下递增
        2. 每一横行从中间到两边依次递减

    因此我们直接从中间对称轴倒序二分找起即可!

        C(r, k)对应的顺序值为:(r + 1) * r / 2 + k + 1

        二分的左右端点:l:2k,r:max(n, l)
            右端点一定不能比左端点小!
            特例:否则当n=1时,会出问题!

*/
// C(a, b) = a!/b!(a-b)! = a * (a-1) .. b个 / b!
LL C(int a, int b){
    LL res = 1;
    for(int i = a, j = 1; j <= b; i --, j ++){
        res = res * i / j;
        // 大于n已无意义,且防止爆LL
        if(res > n) return res;
    }
    return res;
}

bool check(int k){
    // 二分该斜行,找到大于等于该值的第一个数
    // 左边界2k,右边界为max(l, n)取二者最大即可!
    int l = 2 * k, r = max(n, l);
    while(l < r){
        int mid = l + r >> 1;
        if(C(mid, k) >= n) r = mid;
        else l = mid + 1;
    }
    if(C(r, k) != n) return false;
    // C(r, k)的从0开始的顺序!
    cout << 1ll * (r + 1) * r / 2 + k + 1 << endl;
    return true;
}

int main(){
    cin >> n;
    // 从第16斜行枚举即可!
    for(int k = 16; ; k --)
        if(check(k)) break;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

理工大猪猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值