问题:输入一个数N,求N第一次在杨辉三角中出现的位置。
因为杨辉三角是左右对称的,因此本篇我们只关注杨辉三角左半边的部分。杨辉三角第row行col列的元素值等于组合数C(row, col),例如第6行第3列元素等于C(6, 3) = 20。另外,如果一个数在杨辉三角左半边出现过两次,设出现的位置分别为(row1, col1)和(row2, col2)且col2 > col1,则一定有row1 > row2。根据这个性质我们从大到小遍历每个列,对于一个列我们从小到大遍历每个行并且求该列该行元素的值,如果元素的值超过了N则继续遍历下个更小的列。
#include <iostream>
using namespace std;
long long C(long long n, long long m) { //计算组合数C(n, m)
long long ans = 1;
for (long long i = 1; i <= m; ++i) ans = ans * (n - m + i) / i;
return ans;
}
long long Pos(long long row, long long col) { //计算row行col列的元素是杨辉三角的第几个元素
return (row + 1) * row / 2 + col + 1;
}
int main()
{
long long N;
cin >> N;
long long max_col; //因为是从大到小遍历每列,所以列数需要有个最大值
for (max_col = 0; C((max_col + 1) * 2, max_col + 1) <= N; ++max_col) ; //第col列的起始位置是(col * 2, col),如果(col * 2, col)处的元素大于N,就没必要遍历第col列了
for (long long col = max_col; col >= 0; --col) { //由大到小遍历每一列
if (col == 0) { //特判,如果遍历到第0列直接输出1
cout << "1";
break;
}
if (col == 1) { //特判,如果遍历到第1列直接输出Pos(N, 1)
cout << Pos(N, 1);
break;
}
long long row = col * 2, c = C(row, col); //row是当前行数,c是(row, col)位置的元素
while (c < N) { //遍历每一行直到c不小于N
row++;
c = c * row / (row - col);
}
if (c == N) { //如果c等于N便找到了N第一次出现的位置
cout << Pos(row, col);
break;
}
}
return 0;
}