目录
题目描述
解题思路
1.首先第一种是暴力解法,利用二维数组动态规划算法构建一个99*99的二维数组然后去跑样例,结果帮你们试了最后只得了45分,如果没时间没思路可以直接上暴力求解拿分就走其实无限大的二维数组可以求解但是内存会超时所以我们需要从数学层面上优化算法,下面讲一种拿满分的方法。
2.第二种方法是取一半杨辉三角然后在每一个斜列用二分查找确定位置。二分查找的判定范围用排列数计算,而位置则通过行列数用等差数列求和计算。
第一步,取一半杨辉三角
取一半是因为杨辉三角是关于中心点对称的所以说我们要找的数肯定会先从杨辉三角的左边出现,我们就只保留左边的杨辉三角
第二步,取斜列
我们可以从图中观察可知,斜列存在着某种递增关系,而且后一斜列的值总会比前一斜列的值早在三角形里出现,所以我们可以从斜列里从后往前找。
第三步,在斜列里用二分查找确定位置
从上图我们可以看出,斜列从0开始计数,斜列的每一个第一个值满足对应C(2k,k)其中k对应斜列数而2k对应其三角形横列数。如果某一个数比斜列的第一个值还小那么他肯定不住这个斜列,否则就在该斜列里找。
第四步,确定二分查找的范围
我们拿第三斜列来举例,第一个数满足C(4,2)而第二个数满足C(5,2)第三个数满足C(6,2)依次类推,那么该斜列二分查找的最小端点肯定是C(2*K,K),那么最大端点应该是C(X,K)而X怎么定呢,为了防止出错我们直接用其本身,因为拿15举例C(6,2)肯定小于C(15,2)所以说我们的最大端点要保证覆盖了我们找的那个数,所以我们直接用输入值n,及C(n,k)用作最大边界。
第五步,找到这个数然后确定他的位置
我们通过斜列找到我们要找的那个数后,我们会有他的排列数也就是C(i,j)其中i就是对应横行,j就是对应所在列,我们观察原三角形,从第一行到所在行为等差序列为1的等差数列,用等差数列求和后加上列值既可。求和公式我们用(a1+an)*n/2。
代码
排列数
def A(a,b):
'''组合数'''
n=1
#A(4,2)=4!/2!=4*3=12
#所以A(4,2)就相当于4-2+1到4的阶乘
for i in range(a,a-b,-1):
n*=i
return n
def C(a,b):
'''排列数'''
return A(a,b)//A(b,b)
斜列二分查找
head=2*k#根据规律斜行的第一个数是C(2*K,K)
tail=max(n,head)#一般n都比head大,如果n比head小就直接找C(2*K,K)看是否在不在这一斜行,因为斜行的元素是依次递增的
while head<tail:
mid=(head+tail)//2
if C(mid,k)>=n:
tail=mid#如果中值比输入的n大,那么我们想要的值一定在右半段那么令尾部变成中间
else:
head=mid+1
总代码
def A(a,b):
'''组合数'''
n=1
#A(4,2)=4!/2!=4*3=12
#所以A(4,2)就相当于4-2+1到4的阶乘
for i in range(a,a-b,-1):
n*=i
return n
def C(a,b):
'''排列数'''
return A(a,b)//A(b,b)
def find(k):
head=2*k#根据规律斜行的第一个数是C(2*K,K)
tail=max(n,head)#一般n都比head大,如果n比head小就直接找C(2*K,K)看是否在不在这一斜行,因为斜行的元素是依次递增的
while head<tail:
mid=(head+tail)//2
if C(mid,k)>=n:
tail=mid#如果中值比输入的n大,那么我们想要的值一定在右半段那么令尾部变成中间
else:
head=mid+1
if C(tail,k)!=n:
return False#当二分查找查完了都不是,或者第一个C(2*K,K)也不是那么就在下一个斜行
#没有返回FALSE说明找到了,利用tail==横行和等差数列求和公式可得这个元素的位置
print((tail+1)*tail//2+k+1)
return True
if __name__=='__main__':
n=int(input())
for i in range(16,-1,-1):#从第16斜行到0斜行查找
if find(i):
break