蓝桥杯——杨辉三角分析总结

题目描述

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

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

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

输入描述

输入一个整数 NNN。

输出描述

输出一个整数代表答案。

输入输出样例

示例:输入6,输出13

评测用例规模与约定

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

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

分析总结:获取到杨辉三角,在此基础上查找某个数第一次出现的位置,最初的想法是用vector<vector<long long>>来保存一张很大的杨辉三角,但对于最大测试用例1000000000来说,运算的时间和保存的空间不可接受,且遍历整张表查找元素确实有点可爱。所以从节约空间出发,用一个二维数组只维护上一行和这一行,以递推的形式逐渐向后搜索,与此同时判断当前元素是否是要查找的元素,在递推杨辉三角的过程中可以发现每一行都有对称的情况,所以只需递推出每行的一半即可,

但即使是这样也无法解决n取100000000时的情况,通过观察发现当n比较大时,例如n取14,在递推查找的过程中,当当前行第三列的数大于14时,那么14就只能出现在递增的第二列,因为当前行第三列元素向右和向下都是增加的,此时就可以跳出递推过程,通过数学方法直接计算出n的位子,对于n取14的情况数学公式是(n+1)*(n/2)+(n%2)*(n/2+1)。

编写代码时实际考虑的关系是下图

最终的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<vector>
typedef long long LL;
using namespace std;
LL a[2][23000];//a[0]用来维护第三行,a[1]用来维护第四行,此后a[0],a[1]交替维护
int main()
{
	LL n,flag=0,row=3;//flag是标志为,用于交替执行递推三角函数的代码块,row是当前行
	LL t;//列
	LL index=1;//计数器,统计当前元素是杨辉三角中的第几个元素
	scanf("%lld",&n);
	if(n==1)//对n=1的情况进行特判,因为是从第三行开始递推的
	{
		printf("%d",index);
		system("pause");
		return 0;
	}
	a[0][1]=1;//每一行的第一个元素都是1
	a[1][1]=1;
	index+=2;
	while(true)
	{
		index++;
		if(flag==0){
		for(t=2;t<=row%2+row/2;t++){
			if(t!=row%2+row/2)
			{
				index++;
				a[1][t]=a[0][t]+a[0][t-1];
				//printf("%lld ",a[1][t]);
			}else{
				index++;
			    a[1][t]=2*a[0][t-1];
				//printf("%lld\n",a[1][t]);
			}
			if(a[1][t]==n)
			{printf("%lld",index);system("pause");return 0;}
			if(a[1][3]>n)//观察杨辉三角的第三列发现当第三列是数大于要找的n时,n就只能存在于第2列(按顺序递增的那一列)
			{
				LL sum=0;
				sum=(1+n)*(n/2)+(n%2)*(n/2+1);
				printf("%lld",sum+2);system("pause");return 0;
			}
		}
		index+=row-(row%2+row/2);
		flag=1;
		}
		else if(flag==1)
		{
			for(t=2;t<=row%2+row/2;t++){
				a[0][t]=a[1][t]+a[1][t-1];
				index++;
				//printf("%lld ",a[0][t]);
				if(a[0][t]==n)
			{printf("%lld",index);system("pause");return 0;}
				if(a[0][3]>n)
				{
					
				  LL sum=0;
				sum=(1+n)*(n/2)+(n%2)*(n/2+1);
					printf("%lld",sum+2);system("pause");return 0;
				}
		}
			index+=row-(row%2+row/2);
			//printf("\n");
			flag=0;
		}
		row++;
	}
	system("pause");
	return 0;
}

 在实际提交测试的过程中发现,对于这道题最容易出错的是对数据取值范围,对于数据比较大的情况,除了将用到的数据类型定义成longlong型,a数组的中每行的列数定义成多少关乎是否越界导致错误,预估数据规模是很重要的,根据上面的规律,当前行的第三列大于1000000000是在第44723行,该行保存的元素44723/2=22362个,故数组a定义的列数至少要大于22362,才不会溢出,一旦溢出,前功尽弃。细节!!

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值