蓝桥杯历届真题 杨辉三角形【第十二届】【省赛】【B组】

8 篇文章 0 订阅
7 篇文章 0 订阅

蓝桥杯历届真题 杨辉三角形【第十二届】【省赛】【B组】

题目链接-蓝桥杯历届真题 杨辉三角形在这里插入图片描述在这里插入图片描述

题目大意
将杨辉三角形按照从上到下、从左至右的顺序排成一个数列。输入一个正整数 N N N,请你判断该数列中第一次出现 N N N是数列中第几个数。
解题思路

  • 思路一

    找 规 律 找规律
          1 1 1
          1 1 1   1 1 1
          1 1 1   2 2 2   1 1 1
          1 1 1   3 3 3   3 3 3   1 1 1
          1 1 1   4 4 4   6 6 6   4 4 4   1 1 1
          1 1 1   5 5 5   10 10 10   10 10 10   5 5 5   1 1 1

  1. 观察上面杨辉三角形,可以发现第一列全是 1 1 1,第二列为从 0 0 0开始每次递增 1 1 1的递增序列,第三列为序列 1 、 2 、 3 … n 1、2、3…n 123n(即第二列)的前缀和序列。

  2. 由于 N N N的最大是 1 e 9 1e9 1e9,第一列全为 1 1 1,不用考虑,第二列每次递增 1 1 1,若要达到最大值,定义数组的内存肯定超限。然后第三列通过计算 n ∗ ( n + 1 ) / 2 > 1 e 9 n*(n+1)/2>1e9 n(n+1)/2>1e9可以得到 n > 44721 n>44721 n>44721,由于第三列第一行和第二行都为 0 0 0,所以最小需要44723行。

  3. 当第三列的值已经大于 1 e 9 1e9 1e9时,不需要再计算后面的数,直接根据第二列规律,找第二列中 n n n的位置即可。由于第二列是从 0 0 0开始的,此时可以确定 n n n是在第 n + 1 n+1 n+1行,又因为是第二列,所以 n n n的是数列中第 n ∗ ( n + 1 ) / 2 + 2 n*(n+1)/2+2 n(n+1)/2+2个。

    附上代码

    #pragma GCC optimize("-Ofast","-funroll-all-loops")
    #include<bits/stdc++.h>
    #define int long long
    #define lowbit(x) (x &(-x))
    #define endl '\n'
    #define debug(x) cout<<"# "<<x<<endl;
    using namespace std;
    const int INF=0x3f3f3f3f3f3f3f3f;
    const int dir[4][2]={-1,0,1,0,0,-1,0,1};
    const double PI=acos(-1.0);
    const double e=exp(1.0);
    const double eps=1e-10;
    const int M=1e9+7;
    const int N=2e5+10;
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef unsigned long long ull;
    int a[N];
    signed main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    
    	int n,k=1;
    	cin>>n;
    	a[0]=1;
    	if(n==1) cout<<1<<endl;
    	else{
    		for(int i=1;i<44725;i++){
    			for(int j=i;j>=1;j--){
    				a[j]+=a[j-1];
    				if(a[j]==n){
    					cout<<k+i-j+1<<endl;
    					return 0;
    				}
    			}
    			k+=(i+1);
    		}
    		cout<<(1+n)*n/2+2<<endl;
    	}
    	return 0;
    }
    
  • 思路二
    二 分 + 组 合 数 二分+组合数 +
  1. 根据杨辉三角形与组合数的联系,第 i i i行第 j j j列的数都是组合数 C ( i , j ) C(i, j) C(i,j),因为 C ( n , 1 ) = n C(n, 1) = n C(n,1)=n,所以对于每个输入的 n n n必定有解。

  2. 由于杨辉三角形是左右对称的,且数列是按照每行从左到右排列的,所以数字第一次出现必定在左边。
            1 1 1
           1 1 1
          1 1 1 2
         1 1 1 3
        1 1 1 4 6
       1 1 1 5 10
    1 1 1 6 15 20

  3. 根据题意 n n n最大 1 e 9 1e9 1e9,且 C ( 34 , 17 ) > 1 e 9 C(34, 17) > 1e9 C(34,17)>1e9 C ( 32 , 16 ) < 1 e 9 C(32, 16) < 1e9 C(32,16)<1e9,因此只要枚举前 16 16 16个斜行即可

  4. 观察上面三角形可以看出,除了第一条边,一条边上的数都是严格单调递增的,所以我们可以对每一条边进行一次二分操作

  5. 组合数计算需要用数学公式 C ( n , m ) = n ! ( n − m ) ! ∗ m ! = ( n − m + 1 ) ( n − m + 2 ) ∗ … ∗ n 1 ∗ 2 ∗ … ∗ m C(n,m)=\frac{n!}{(n-m)!*m!}=\frac{(n-m+1)(n-m+2)*…*n}{1*2*…*m} C(n,m)=(nm)!m!n!=12m(nm+1)(nm+2)n直接算,如果数组的话会超内存。
    附上代码

    #pragma GCC optimize("-Ofast","-funroll-all-loops")
    #include<bits/stdc++.h>
    #define int long long
    #define lowbit(x) (x &(-x))
    #define endl '\n'
    #define debug(x) cout<<"# "<<x<<endl;
    using namespace std;
    const int INF=0x3f3f3f3f3f3f3f3f;
    const int dir[4][2]={-1,0,1,0,0,-1,0,1};
    const double PI=acos(-1.0);
    const double e=exp(1.0);
    const double eps=1e-10;
    const int M=1e9+7;
    const int N=2e3+10;
    typedef long long ll;
    typedef pair<int,int> PII;
    typedef unsigned long long ull;
    int C(int a,int b,int n){
    	int ans=1;
    	for(int i=a,j=1;j<=b;i--,j++){
    		ans=ans*i/j;
    		if(ans>n) return ans;
    	}
    	return ans;
    }
    bool check(int k,int n){
    	int l=2*k,r=max(n,l);
    	while(l<r){
    		int mid=(l+r)/2;
    		if(C(mid,k,n)>=n) r=mid;
    		else l=mid+1;
    	}
    	if(C(r,k,n)!=n) return false;
    	cout<<(r+1)*r/2+k+1<<endl;
    	return true;
    }
    signed main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    
    	int n;
    	cin>>n;
    	for(int i=16;i>=0;i--){
    		if(check(i,n)) break;
    	}
    	return 0;
    }
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值