杨辉三角规律

杨辉三角规律_第1张图片
杨辉三角规律_第2张图片
图片来自acwing
1、首先要知道N第一次出现在第几个数,即要累计前面出现过的所有数
这里杨辉三角一列的数量是无穷的,只能通过确定n出现的行数来计算
2、杨辉三角的规律有:
一、左右对称,于是以下聊的都是在左半部分杨辉三角内的规律
为了更好表达规律,将 杨辉三角逆时针旋转45°得到的三角形称作 杨辉三角

二、杨辉三角每个斜列(杨辉三角从左往右第x列)的第一个元素大小为C(x*2,x),
且 从左到右 每列的第一个元素是递增的 ,每一列从上到下也是递增的

要确定n所在的行,那么这一行的最后一个元素一定>=n
杨辉三角 某一行(第i行)的最后一个元素 就是
杨辉三角某个斜列(也就是杨辉三角某列的第一个元素),具体是第几列呢?

重要的规律来了,对于杨辉三角中这特殊的一部分元素——
每个斜列的第一个元素(每行最后一个元素) ,在杨辉三角中 行数下标是列数下标的2倍
(值是可以通过C(x*2,x)计算的,有递增性可以二分,所在的行列关系非常清楚)

总结就是杨辉三角中其实每个位置(i,j)(行列下标都从0开始)的值都可以求出来,是
C(i,j),而当只考虑杨辉三角的左半部分,每一行都是递增的,
且每一行的最后一个元素行号等于列号的2倍

#include 
/*#include 
#include 
#include */
#define int long long 
using namespace std;
const int N=20;
int a[N][N];
void print(){
	for(int i=0;i<=N;i++)a[i][0]=1;//第0列全1 
	for(int i=1;i<=N;i++){
		for(int j=1;j<=i;j++){
			a[i][j]=a[i-1][j-1]+a[i-1][j]; 
		}
	}	
	for(int i=0;i<=N;i++){
		for(int j=0;j<=i;j++){
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
} 
const int inf=0x3f3f3f3f;
int n; 
int res=inf;
int C(int a,int b){//C(5,2)=5*4/2/1
	int res=1;
	for(int i=a,j=1;j<=b;j++,i--){
		res=res*i/j;//边乘边除
		if(res>n)return res;//防止爆long long,反正大于n也不可能取这个值 
	}
	return res; 
}
bool fun(int k){//第k列
	int l=k*2;//每列第一个元素所在的行是列数*2噢
	int r=n;//根据第一列,n最晚出现在第n行
	while(l<r){
		int mid=(l+r)>>1;
		if(C(mid,k)<n){//第k列,mid这一行 小于n,这列有n就在下面 
			l=mid+1; 
		}
		//要是判断条件写成<=,则l=mid,要写成mid=(l+r+1)<<1 
		else r=mid;
	} 
/*	if(C(l+k,k)==n)return l*(l+1)/2+k+1;//加1是因为从0开始的
	else return inf;*/ 
	if(C(l,k)==n){
		cout<<r*(r+1)/2+k+1;
		return true;
	}
	return false;
//行数、列数指的都是在杨辉三角中的行列 !!!
//所以不是C(mid+k,k)	而是C(mid,k)
}
signed main() {
/*观察杨辉三角规律
1、原杨辉三角左右对称,某数第一次出现一定在左半边,前若干列
2、左右对称则从中间劈开,只看左半边,可发现中线上的元素的值
1 2 6 20,C(0*2,0),C(2,1),C(4,2),C(6,3)…
C(2*k,k),k=0,1,2,3…,当摆放成下三角形形式,k代表的就是列数
其实拟合第4条,也可以得知每列第一个元素位于的行数等于列数*2!
注意了 行数、列数指的都是在杨辉三角中的行列 !!! 
中线上的元素就是每列的从上往下第一个元素,也是该列最小的元素(每列从上往下递增)
以上这些感觉打印出下三角也不太好看,不太好劈成两半看,还是自己多补几行原杨辉三角
3、每列从上往下递增嘛,第1列的是差值为1的等差数列,所以n在杨辉三角中一定会存在,
最晚出现在第n行,这也将成为  二分 在每列中找到n出现的行 的依据(递增,行的上限) 
4、摆放成下三角形形式,m行n列的元素大小是C(m+n,n),行大于列,从0开始计数! 
在原杨辉三角里, m行n列的元素大小是C(m,n)!!! 
5、有这样的规律,C(34,17)就会超过1e18,所以只需要考虑前17列就ok 
总而言之,这题重在找到杨辉三角的规律 
*/
 	//print();
 	cin>>n;
 	for(int i=17;i>=0;i--){
 		if(fun(i))break;
 		//int ans=fun(i);
 		//if(ans
 	}
 	/*从右往左枚举列,因为左半边三角形 每行从左往右递增,
	 第一次出现的位置自然需要行数尽可能小,如果第i列有n,
	 那么小于i的那些列里,n一定出现在下面,因为同行小于i列该行的值*/ 
 	//cout<
	return 0;
}

你可能感兴趣的:(二分,c++)