蓝桥杯题解——杨辉三角形
题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, \cdots1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯
给定一个正整数 NN,请你输出数列中第一次出现 NN 是在第几个数?
输入描述
输入一个整数 NN。
输出描述
输出一个整数代表答案。
输入输出样例
示例 1
输入
6
输出
13
评测用例规模与约定
对于 20%20 的评测用例,1\leq N\leq 101≤N≤10; 对于所有评测用例,1\leq N\leq 10000000001≤N≤1000000000。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
public class Main {
static int N;
/**
* 求组合数<br/>
* C_n^m = [n*(n-1)*...*(n-m+1)] / [1 * 2 * ... * m]
* @param m 选几个球?
* @param n 从几个球中选?
* @return 选择方案数
*/
static long C(int m, int n){
long res = 1;
for(int i = n, j=1; j<=m;j++,i--){
res *= i;
res /= j;
//如过算出来已经大于N了,继续算不仅没意义,而且会越界,出现负数,扰乱判断
if(res > N){
return res;
}
}
return res;
}
/**
* 在这一列中搜索N第一次出现的位置
* @param column 当前搜索的列数
* @return N第一次出现的位置,没出现就返回-1
*/
static long searchFirstAppearByColumn(int column){
// 这一列的第一个元素是在2column处
int left = 2 * column;
//搜索到第N行就可以停止了
//这里注意一下,如果搜索1,那么在第1列的时候,左边界是2,N是1
//如果右边界是N的话最后搜索到的就是第1行第1列的1,那么输出结果就会变成3,这明显是不成立的
//所以我们要保证开始搜索时左边界要小于等于右边界
int right = Math.max(N,left);
int mid = (left + right) >> 1;
//暂存计算结果
long tmpResult;
//二分搜索
while(left <= right){
//位运算,相当于浅浅加个速,但是加了不少逼格
mid = (left + right) >> 1;
tmpResult = C(column,mid);
//找到了就退出循环
if(tmpResult == N){
break;
}
if(tmpResult > N){
//如果找的数过大了,就从左区间继续找,为了避免死循环,右边界要减1
right = mid-1;
}else{
//为了避免死循环,左边界要加1
left = mid+1;
}
}
//如果找到了的值确实是N
if(C(column, mid) == N){
//right是行号
return (long) (mid) *(mid +1)/2 + column + 1;
}
return -1;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
N = scanner.nextInt();
long ans;
for(int i = 16 ;i >= 0;i--){
//赋值完来个比较,不是-1就是找到了,返回其位置
if((ans = searchFirstAppearByColumn(i)) != -1){
System.out.println(ans);
break;
}
}
}
}