杨辉三角
思路:
1.由于左右对称可以直接看左半边
2. 组合数和杨辉三角:第i行第j列的数都是组合数C(i, j) (i,j从0开始)
C(n, 1) = n --> 对应从左向右看斜着的第二列! —> 一定有解
由于杨辉三角左右对称(C(a, b) == C(a, a-b)),又由于找第一次出现,因此一定在左边,右边可以直接删掉!1 ---> C(0, 0) 1 1 2 ---> C(2, 1) 1 3 ---> C(2n, n) 1 4 6 ---> C(4, 2) 1 5 10 1 6 15 20 ---> C(6, 3)
n最大1e9,C(34, 17) > 1e9, C(32, 16) < 1e9,因此只要枚举前16个斜行即可!
性质:
1. 每一斜行从上到下递增
2. 每一横行从中间到两边依次递减 因此我们直接从中间对称轴倒序二分找起即可! C(r, k)对应的顺序值为:(r + 1) * r / 2 + k + 1 二分的左右端点:l:2k,r:max(n, l)
右端点一定不能比左端点小!
特例:否则当n=1时,会出问题!
样例输入:
6
样例输出:
13
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n;
//暴力求组合数
LL c(int a, int b)
{
LL t = 1;
for(int i = 1, j = a; i <= b; i ++, j -- )
{
t = t * j / i;
}
return t;
}
//二分查找
bool check(int u)
{
LL l = u * 2, r = n;
while(l < r)
{
LL mid = (l + r) >> 1;
if(c(mid, u) < n) l = mid + 1;
else r = mid;
}
if(c(l, u) == n)
{
cout << l * (l + 1) / 2 + u + 1 << endl;
return true;
}
return false;
}
int main()
{
cin >> n;
for(int i = 16; i >= 0; i -- )
if(check(i))
break;
return 0;
}