杨辉三角形【第十二届】【省赛】【研究生组】

首先看一下这道题,我以为能够找出什么规律,还小小地写了一下前几行,渴望能够找到O(1)的答案。

注意:以下所有和数组有关的都是从0开始的,0行0列是存在的!

但是我发现这很难,后来我到处找题解,发现原来杨辉三角的规律是 yh[i][j] = C_i^j

 

好,知道规律了,又怎么样呢?难道要一个个枚举i和j直到找到答案吗。这时很多题解都想到了及时止损,也就是说既然越往下越大,那么如果在某一斜列就已经大于1e9(给定的最大数据范围)了,那么也不必再往下一点点计算找出杨辉三角的数了。所以我们找一个值,看看在哪个位置第一次出现比1e9大的数。结果发现在yh[2000][3] = C_{2000}^3 > 1e9。那太好了,这一位置对应的更往下的斜列肯定会更大于1e9,也就是说yh[2001][3] = C_{2001}^3 > yh[2000][3]>1e9.

那么现在就可以分为三种情况讨论了:

 

1.在杨辉三角的前2001(从0到2000)行中,计算一下,把前2001行填到数组中,如果恰好找到了n = yh[i][j],那么就太好了。但是题目要求的是这个n在数列中出现的位置,我们怎么求呢?

幸好杨辉三角还有规律,就是第0行有1个数,第1行有2个数,那么第i行之前有多少个数呢?原来是:num = (1 + i) * i / 2.

第i行之前有这么多个数,那么第i行第j列呢?原来是:num = (1 + i) * i / 2 + (j + 1).

好,第一种情况我们找到了。

那如果不在前2001行出现怎么办呢?那说明在之后的某一行的第1个数或者第2个数(每行的第0个数是1)。为什么这么说呢,因为第2001行的第3个数已经yh[2000][3]>1e9了,再往下走肯定还是大于1e9啊,更找不到我们想要的n了。所以我们现在就要在某一行的第1列或者第2列找到这个数。

 

 

2.某一行的第二列:yh[a][2] = C_a^2.好,那么我们如何找到这个a呢,观察一下这个等式的结果:

yh[a][2] = C_a^2 = \frac{a!}{2!(a-2)!} = \frac{a*(a - 1)}{2}=n =>a = sqrt(2 n) + 1

找到a了!那么就来看看这个C^2_a = n?如果等于,太好了,找到了!

现在看看找到的话n在序列中的位置:(1 + a)*a/2 + 3.(注意是第2列,所以加3)。

不等于,那只好去找最后一种情况了。

 

3.某一行的第一列:yh[a][1] = C_a^1.我们通过观察杨辉三角可以知道第a行的第1列的数不就是a本身吗。那么如果n就是第n行第1列的数,就很好求了。

从第0行到第n-1行一共多少个数:(1 + n) * n /2.

那么第n行第1列在数列中对应的元素个数,也就是我们要的结果就是:(1 + n) * n /2 + 2.

 好,现在三种情况都找到了!开始写代码吧。

对了!记得对1做一个特判,不然会报错!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<cmath>
#define ll long long
using namespace std;
int yh[2005][2005];
int main(){
	ll n;
	cin>>n;
	memset(yh, 0, sizeof(yh));
	if(n == 1){
		cout<<1<<endl;
		return 0;
	}
	yh[0][0] = 1;
	for(int i = 1; i < 2001;i++){
		yh[i][0] = 1; 
		for(int j = 1; j <= i; j++){
			yh[i][j] = yh[i - 1][j - 1] + yh[i - 1][j];
			if(yh[i][j] == n) {
				cout<<i * (i + 1) / 2 + j + 1<<endl;
				return 0;
			}
		}
	}
	// n * (n - 1) / 2 == N
	ll a = sqrt(n * 2) + 1;
	if(a * (a - 1) / 2 == n){
		cout<<a * (a + 1) / 2 + 3<<endl;
		return 0;
	}else{
		cout<<n * (n + 1) / 2 + 2<<endl;
		return 0;
	}
	return 0;
} 

好了,这就是这道杨辉三角题了。本菜鸡为了cv这道题找了好多题解,感谢各位大神的题解!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值