杨辉三角形是对称的,所以在右半部分出现了,左半部分一定先出现,就可以只考虑一行的一半数据
1 1
1 1 -》》》》》》》 1
1 2 1 1 2
1 3 3 1 1 3
1 4 6 4 1 1 4 6
可以发现,每i列的有效位置是从 第2*i行开始 (列和行从0开始),并且第i行,j列的数 等于N =i, M = j的组合数, 则可以采用二分法的方法从第16列(列从0开始算)的有效位置也就是2i行 ~ n行 (因为当列为17,行为2*i 也就是34的时候,数值已经大于输入的10^9次方,从16列开始依次往前找),
数据在同一列的时候,单调递增, 那么就可以采用二分法查找n (O(logn)时间复杂度),当前列没找到数据,则到上一列的有效位置继续找,直到找到为止。
找到后指定行数和列数,就可以计算n值在第几个数上(等差数列求和 )
函数C是计算组合数:根据以下公式推出:(m为列号,n为行号)
C函数则是 乘一次分子,除一次分母,能够很好的防止数据溢出
蓝桥杯讲师的代码(c++)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int C(int a , int b){
int res = 1;
for(int i = a , j = 1 ; j <= b ; i -- , j ++){
res = res * i / j;
if(res > n) return res;
}
return res;
}
signed main()
{
cin >> n;
for(int k = 16 ; ~k ; k --){
int l = 2 * k , r = max(n , l) , res = -1;
while(l <= r){
int mid = l + r >> 1;
if(C(mid , k) >= n) res = mid , r = mid - 1;
else l = mid + 1;
}
if(C(res , k) == n) return cout << (res + 1) * res / 2 + k + 1 << '\n' , 0;
}
return 0;
}
Python版本
n = 0
def c(a, b):
ans = 1;
i = a
j = 1
while j <= b:
ans = ans * i / j
i -= 1
j += 1
return ans
row = -1
column = -1
n = int(input()) #c 34行17列 > 10^9
isFind = False
for i in range(17, -1, -1):
left = 2 * i
right = max(left, n)
while left <= right:
mid = (left + right) // 2
ans = c(mid, i)
if ans == n:
row = mid
column = i
isFind = True
break
elif ans > n:
right = mid - 1
else:
left = mid + 1
if isFind:
break
print( (row + 1) * row // 2 + column + 1 )