刚开始是用了数组存储查找,会超时,只能通过30%的案例;
然后看了CSDN两位大佬的思路和解法(二项式是真的六啊,,,):
第十二届蓝桥杯B组C/C++省赛—H题(杨辉三角)_思维题_萌小帝的博客-CSDN博客
求杨辉三角中元素首次出现位置【2021蓝桥杯】_LMoon琉月的博客-CSDN博客_杨辉三角形某个数第一次出现
(但是用纯C语言去写还是会超时,所以自己做了一些修改)
关于二项式的思路,两位大佬的文里面都有详细的讲解,我这里就不再班门弄斧。
直接上代码,关于修改的地方和需要注意的地方代码中有注释。
#include<stdio.h>
long long g[20]={0};//用于存储阶乘分母
long long mymax(long long a,long long b)//两值中找最大值;
{
if(a>=b)
return a;
else
return b;
}
long long binomial(int a,int k,long long n)/*(a,k分别是C(n,k)里面的n和k;)这里使用二项式计算杨辉三角中的值,但是定义了一个n,因为二项式的计算是(n*(n-1)*(n-2)*...*(n-k))/k!
用g[k]存储了k!,然后在下面的循环中计算1/g[k] *a*(a-1),一旦乘积大于了n,就没有继续计算下去的必要了,直接跳出,这样就能减小运算时间。*/
{
int i;
long long f=1,gg=1;
if(g[k]==0)
{
for(i=1;i<=k;i++)
{
gg=gg*i;//分母
}
g[k]=gg;
}
for(i=0;i<k;i++)
{
f=f*(a-i);
if(f/g[k]>n)
{
break;
}
}
return f/g[k];
}
int localmax(long long n)/*这里计算出到第几斜行的第一个元素是大于n值的,那第一个n值出现的位置一定是在该斜行的左边*/
{
int k;
for(k=1;k<=100;k++)
{
if(binomial(2*k,k,n)>n)
{
break;
}
}
return k;
}
long long erf(int k,int min,long long n)/*二分查找,减小时间复杂度*/
{
int l=min;
long long r=mymax(l,n);
while(l<r)
{
long long mid=(l+r)/2;
if(binomial(mid,k,n)>=n)
{
r=mid;
}
else
{
l=mid+1;
}
}
if(binomial(r,k,n)!=n)
return 0;
else
return r;/*返回所在行-1的数*/
}
int main()
{
int maxk,i,a,k;
long long n;
scanf("%lld",&n);
if(n==1)
{
printf("1");
return 0;
}
maxk=localmax(n);
for(i=maxk-1;i>0;i--)
{
if(erf(i,2*i,n))
{
k=i;
a=erf(i,2*i,n)+1;
break;
}
}
long long order=0;
for(i=1;i<a;i++)
order=order+i;
order=order+k+1;
printf("%d %d\n",k,a);//这里为了方便理解所以输出了斜行数和层数,测试时记得注释掉
printf("%lld",order);
return 0;
}