P8749(杨辉三角)
H2130819068 · · 个人记录
做题笔记
该题使用到了组合数的O(n)级别计算方法,还有杨辉三角的相关性质。
杨辉三角的性质如下:
杨辉三角有 第0层, 所以第n层,与第n行含义不同 第n行 为第n-1 层,下面结论 要分辨 行与层
第0层 1
第1层 1 1
第2层 1 2 1
第3层 1 3 3 1
第4层 1 4 6 4 1
第5层 1 5 10 10 5 1
第6层 1 6 15 20 15 6 1
第7层 1 7 21 35 35 21 7 1
第8层 1 8 28 56 70 56 28 8 1
第9层 1 9 36 84 126 126 84 36 9 1
每一层对应元素为
C(n,0) C(n,1).....C(n,n-1) C(n,n);
根据数位于的层数和对角线数可以计算数是第几个。
例如:C(n,m) 就是位于第n层第m个对角线的数, (n+1)*n/2+m+1就是该数字对应的位置。
每一个对角线开头的元素都符合C(2k,k)条件,且对角线上,后面的数一定大于前面的数。注:k为任意常数。
本题中的数据最大为10^9,C(32,16)已经大于10^9,所以下面的代码中我们只需要枚举0—16即可。
AC代码如下:
#include<iostream>
using namespace std;
typedef long long LL;
int n;
LL C(LL a,LL b)//计算组合数的值
{
LL ans=1;
for(int i=1;i<=b;i++)
{
ans=ans*(a-b+i)/i;
if(ans>n)return ans;//题目特殊只需知道ans和n的大小关系就行
}
return ans;
}
int main()
{
cin>>n;
if(n==1)
{
printf("1");
return 0;
}
for(int i=16;i>=0;i--)
{
if(C(2*i,i)<=n)//遍历对角线的开头,因为后面的数一定比开头大
{
LL mid,l=i,r=1000000005;
while(l<r)//二分查找该对角线下的对应答案;
{
mid=(l+r+1)>>1;
LL t=C(mid,i);
if(t==n)
{
printf("%lld",(mid+1)*mid/2+i+1);//计算第mid层,第i条对角线数据是第几个;
//需要注意的是杨辉三角最上层是第0层;
return 0;
}
else if(n>t)l=mid;
else r=mid-1;
}
}
}
return 0;
}