回顾题意:
也就是说,找到最小的一种进位制
a
,使得数
那么题意立马想到若干个问题:
- 这样的 a 是否一定存在?是否唯一
给定
k , a 是否存在?(反过来呢?单调性有木有?)带着这些问题下面是我思考的全过程:
思路1
首先必须说明的是,这样的good base是存在最小的,这是因为我总可以让
现在来观察
n
的形式,可以发现
大致估计了下,约数的个数应该是相对于 n 来说是灰常小的,比如20亿以内的数,最多的约数只有1536个。或者我们可以直接估算其数学期望:一个不大于n的正整数的约数个数期望意义下是多少?,对于一个自然数
等会,似乎和约数的个数并没有太大的关系,首先我们必须把约数求出来,在求出来的过程中完全可以边进行判断,这说明刚才的思考似乎是没有起到作用的。那么要找
n
的约数
思路1(改进1:二分查找)
实际上,似乎不应该思维卡在约数问题上,对于大数,即使是题目的数上界
1018
也好,一个对数下来也才几十位,换句话说,我们不妨先去遍历
k
,然后对
总算法复杂度是 O((logn)2) ,复杂度看起来灰常好,但是很遗憾一波提交TLE。嗯?原来是对于幂次 ak+1 溢出了,不过讲道理,我看到有人开大数后是可以AC的,这就很尴尬了。
思路1(改进2:对数形式)
对于指数形式溢出的问题,我改进了一下将问题从指数形式变成对数形式,即考虑:
这次应该可以了吧,总算法复杂度也是 O((logn)2) ,兴高采烈地,一波提交WA。嗯?再看详细情况,结果发现106个样例已经过了98个了,额,要是OI的话我就不继续做了,反正拿了90%的分数。慢慢debug发现,原来是eps的问题,原来取对数之后误差也随之变小了,比如5和4本来相差1,但是ln5和ln4相差0.22314,而改进1中并没有这个问题是因为指数会放大误差,随意一个eps基本上都没有问题。
还有一些问题,实际上两种形式都是单调的,对 a 二分,理论上都是有唯一解的,但是对数形式减少了误差后,对于一些诡异的数就会使得二分收到邻近的解上。
思路1(改进3:结合)
这就很尴尬了,那么改进1改进2结合起来呢?就是对于大数,用对数形式,对于小数用指数形式,可以的,提交一波TLE,嗯?原来在区分大数小数的界随意定还是不行,可怕的样例(是谁搞的那么缜密的样例)
思路2(牛顿迭代法)
下午和狗蔡吃饭的时候,想到了能不能直接对对数形式:
来求方程呢?而且对数形式关于 a 的导数是很容易写出来的,做一个迭代
思路3(非数值数学方法)
看了下讨论,发现有大佬的神做法,先给出一个结论,如果
n
能表示为
实际上这是容易证明的,首先注意到
即 a>n√k−1 ,由两个不等式,立马有 a=[n√k] ,接下来就厉害了,对 k 进行遍历,直接求出
class Solution(object):
def smallestGoodBase(self, n):
n = int(n);
for k in xrange(int(math.log(n, 2)), 1 , -1):
a = int(n ** k ** -1)
if (1 - a ** (k + 1)) // (1 - a) == n:
return str(a)
return str(n - 1)
纪念一个血色的一天: