解题思路一 缩小查找范围法
1.首先将三角形转换为如下形式:
2.观察规律:
设行数为a,列数为b,f(a,b)为每个位置上的值
则f(a,1)=1,f(a,2)=a-1,f(a,3)=(1+a-2)(a-2)/2=(a-1)(a-2)/2
3.进行分析:
评测用例给出的最大值为1000000000(10亿)
将其带入f(a,3)可得a=44722.86
即f(44722,3)<10亿,f(44723,3)>10亿
又可以看到当a>4时,f(a,3)>f(a,2)
所有我们在进行搜索时,只需要搜索到44722行即可
超过f(44722,3)的数字必定在第2列,因此可以通过f(a,2)表达式计算它所在的行数
4.实现代码:
# include <stdio.h>
typedef long long LL;
LL N[44722];
LL num;
bool check(LL n,int i,int j)
{
if(n==num)
{
printf("%I64d",(LL)((i-1)*i/2+j));
return true;
}
else return false;
}
int main()
{
scanf("%I64d",&num);
N[1]=1;
if(num==1)
{
printf("1");
return 0;
}
for(int i=2;i<=44722;++i)
{
if(i%2==0)
{
for(int j=i/2;j>1;--j)
{
N[j]+=N[j-1];
if(check(N[j],i,j))return 0;
}
}
else
{
for(int j=i/2+1;j>1;--j)
{
if(j==i/2+1)N[j]=2*N[j-1];
else N[j]+=N[j-1];
if(check(N[j],i,j))return 0;
}
}
}
printf("%I64d",(LL)((num+1)*num/2+2));
return 0;
}
解题思路二 斜行查找法
1.首先将三角形转换为如下形式:
其中每一列相当于原三角形的一斜行
2.观察规律:
设行数为a,列数为b,f(a,b)为每个位置上的值,查找的数字为n
当a>=2b-1时,f(a,b)>{x<=a,y<b|f(x,y)},且f(a,b)=C(a-1,b-1)
当b>1时,f(a+1,b)>f(a,b)
当a<=b/2时(四舍五入),f(a,b+1)>f(a,b)
3.进行分析:
因为第二列为首项为1公差为1的等差数列,所以f(n+1,2)=n,也就是说n必然出现在第2列第n+1行。又因为每一列新出现的值是从2b-1行开始的,所以我们每一列查找的范围应该是从第2b-1行到第n行,即{a|2b-1<=a<=n}。
评测用例给出的最大值为1,000,0。00,000(10亿)。当b=14时,f(2b-1,b)=6,227,020,800。当b=13时,f(2b-1,b)=479,001,600。所以我们只需检查第13列到第3列。
因为每列从上往下单调递增,所以我们可以用二分法检查每一列。
3.实现代码:
# include <stdio.h>
typedef long long LL;
LL num;
LL cbn(LL x,LL y)
{
LL ans=1;
for(LL i=x-y+1,j=1;j<=y;++i,++j)
{
ans=ans*i/j;
if(ans>num)break;
}
return ans;
}
bool check(LL col)
{
LL L=2*col-2;
LL R=num-1;
while(L<=R)
{
LL mid=L+(R-L)/2;
if(cbn(mid,col-1)>num)R=mid-1;
else if(cbn(mid,col-1)<num)L=mid+1;
else
{
printf("%I64d",((1+mid)*mid/2+col));
return true;
}
}
return false;
}
int main()
{
scanf("%I64d",&num);
if(num==1)
{
printf("1");
return 0;
}
for(int i=13;i>=3;--i)
{
if(check(i))return 0;
}
printf("%I64d",((1+num)*num/2+2));
return 0;
}