题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 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,才不会溢出,一旦溢出,前功尽弃。细节!!