下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, ...
给定一个正整数 N,请你输出数列中第一次出现 N 是在第几个数?
输入格式
输入一个整数 N。
输出格式
输出一个整数代表答案。
数据范围
对于 20%的评测用例,1≤N≤10;
对于所有评测用例,1≤N≤109。
输入样例:
6
输出样例:
13
题意:
求N在杨辉三角中最早出现的位置
分析:
1.分析这题我们得看斜行
2.由于对称性且要求最早出现,那么我们答案只可能出现在对称轴的左边
3.看第二斜行可得答案一定有解
4.因为N小于1e9,且C(32,16)<1e9,C(34,17)>1e9,所以N只可能在1~16斜行
5.要求N出现的最早位置,我们应该从第16斜行开始找,为啥嘞?因为如果在越后一斜行找到,那么N所在的列数就越小,为啥嘞?因为在它是在那个位置最大的数了,其他跟它同一行以及比它小行的数都比他小。
6.怎么判断N是否在枚举的那一行里嘞?由于每一斜行都是单调递增的,因此我们可以考虑二分,设当前斜行为第k,则这一行最小为第一个的值C(k,2k),右边界为C(k,n)(一定大于等于n)。
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int n;
//计算组合数,用ll,如果>n就退出,以防爆ll
ll C(int a,int b){
ll res=1;
for(int i=a,j=1;j<=b;--i,++j){
res=res*i/j;
if(res>n){
return res;
}
}
return res;
}
bool check(int k){
int l=2*k,r=max(n,l);//r原本等于n,但为了特判n==1的情况,因为如果n==1,l就>r,就搞不出来了
while(l<=r){
int mid=(l+r)/2;
if(C(mid,k)>n){
r=mid-1;
}else if(C(mid,k)<n){
l=mid+1;
}else{
cout<<1ll*(mid+1)*mid/2+k+1;//将它转为ll,不然爆int
return true;
}
}
return false;
}
int main(){;
cin>>n;
//从第16斜行开始找,找到就退出
for(int i=16;;i--){
if(check(i)){
break;
}
}
return 0;
}