赞
踩
从上图片中,我们可以看出来这是一个对称图形,所以我们只看左半部分就可以了,我们一行一列去做数据量是1e9这样会很麻烦,所以我们这里做一个思想转换,斜着看,也就是斜行。
如上面图片:
1、我们可以发现每一个斜行越往下的方向是递增的
2、 开始的数字是C的底数是上面的2倍也就是------>C(2k,k)
3、无论横着按行去看还是竖着按列去看,还是斜行去看都是最里面的数是大的,也就是2, 6,20这一列是大的,所以也就是越靠下的斜行,数越大,所以我们再找N的时候,就 要 从下去开始找,这也是为什么后面在代码部分会从后往前去遍历。
4、然后根据数据范围我们可以知道 N最大1e9,C(34, 17) > 1e9, C(32, 16) < 1e9,因此只要枚举前16个斜行即可
- #include<iostream>
- #include<cmath>
-
- using namespace std;
-
- typedef long long ll;
- int n;
-
- ll C(int a,int b)
- {
- ll res = 1;
- // C(a, b) = a!/b!(a-b)! = a * (a-1) .. (a-b)个 / b!
- for(int i=a,j=1;j<=b;j++,i--)
- {
- res = res * i / j;
- //防爆 ll ,res大了也没用 最多1e9
- if(res > n) return res;
- }
- return res;
- }
- //二分
- bool check(int k)
- {
- //这里虽然我们是从斜行枚举,但是我们实际是从第16行开始,往上走
- ll l = 2 * k,r = max(n,2*k);
- while(l < r) //左模板
- {
- int mid = l + r >> 1;
- if(C(mid,k) >= n) r = mid;
- else l = mid + 1;
- }
- //如果没找到 返回false
- if(C(l,k) != n) return false;
- //等差数列求和公式
- cout << r*(r+1) / 2 + k + 1 << endl;
- return true;
- }
-
- int main()
- {
- cin >> n;
- //从第十六行开始枚举
- for(int k = 16;;k--)
- {
- if(check(k)) break;
- }
- return 0;
- }
2k和n都是行号。假如我们要找n这个数,我们一定可以在第n行的第1个数找到,也就是C(n,1),但是这个n可能不是第一个出现的n。例如杨辉三角里面的6这个数,它在(6,1)和(4,2)均出现了,要找第一个出现的6,应该是(4,2)这个。
每个斜行的起点的行号是2k,终点是n。而起点的值是C(2k,k),终点的值是C(n,k)我们要在[2k,n]在这个区间内找到等于n的值
当n=1时,k从16往下检查时,当k=1时,l=2k,r=n=1,因为l>r,会直接跳出二分的while循环
C(r,k)=C(1,1)=1。根据C(1,1)得到的顺序值,此时就会输出1的位置是3,但是这个位置不是第一次出现的位置。正确的位置应该是(0,0)
根据等差数列,第一行是1个数,第二行是二个数,第三行是3个数,依次类推,等差数列求和公式Sn = (首项+末项)*项数 / 2
当为C(4,2) == 6时,r = 4,k = 2,它的前面有4行,前面4行的总个数为1 + 2 + 3 + 4= 10,也就是 (r + 1) * r / 2,再加上它在这行的位置k + 1
欢迎不会的小伙伴留言~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。