解法
参考:https://blog.csdn.net/qq_23997101/article/details/73135615
数学推理题…………………………………………
本质是找a和k,使得:
n
=
1
+
a
+
a
2
+
.
.
.
+
a
k
(
k
>
=
1
)
n=1+a+a^2+...+a^k (k>=1)
n=1+a+a2+...+ak(k>=1)
所以有:
n
>
a
k
⇒
n
k
>
a
n>a^k\Rightarrow \sqrt[k]{n}> a
n>ak⇒kn>a
又知
(
1
+
a
)
k
=
1
+
C
k
1
a
+
C
k
2
a
2
+
.
.
.
+
C
k
k
a
k
≥
n
(1+a)^k = 1+C_k^1a+C_k^2a^2+...+C_k^ka^k\ge n
(1+a)k=1+Ck1a+Ck2a2+...+Ckkak≥n
即有:
a
≥
n
k
−
1
a\ge\sqrt[k]{n}-1
a≥kn−1
综上,如果a进制化后长为k+1,那么
n
k
>
a
≥
n
k
−
1
\sqrt[k]{n}>a \ge \sqrt[k]{n}-1
kn>a≥kn−1,就是:
- n k \sqrt[k]{n} kn为整数时, a = n k − 1 a=\sqrt[k]{n}-1 a=kn−1
- n k \sqrt[k]{n} kn为非整数时, a = ⌊ n k ⌋ a=\lfloor\sqrt[k]{n}\rfloor a=⌊kn⌋
当k越大的时候a越小,k最大有多大呢?
当
a
≥
t
a\ge t
a≥t时,k最大为
a
=
t
a=t
a=t的时候,长度为
⌈
l
o
g
t
(
n
+
1
)
⌉
−
1
\lceil log_t(n+1)\rceil-1
⌈logt(n+1)⌉−1
所以我们现在得到了2条结论:
- k确定时,a怎么选:
- n k \sqrt[k]{n} kn为整数时, a = n k − 1 a=\sqrt[k]{n}-1 a=kn−1
- n k \sqrt[k]{n} kn为非整数时, a = ⌊ n k ⌋ a=\lfloor\sqrt[k]{n}\rfloor a=⌊kn⌋
- t确定时,应该从哪里开始搜: ⌈ l o g t ( n ( t − 1 ) + 1 ) − 1 ⌉ \lceil log_t(n(t-1)+1)-1\rceil ⌈logt(n(t−1)+1)−1⌉
所以算法如下:
- 初始时,t=2,算出一个长度k,再根据k算出一个a(当然这时a明显为2)。
- 如果a满足条件,那么显然它是最小的,返回
- 如果a不满足条件,那下一个k在哪呢?下一个k至少要比当前的k小,并且下一个k算出来的a要大于现在的a,所以有: k = m i n ( k − 1 , ⌈ l o g t + 1 ( n t + 1 ) − 1 ⌉ ) k = min(k-1, \lceil log_{t+1}(nt+1)-1\rceil) k=min(k−1,⌈logt+1(nt+1)−1⌉)
有一个坑是k=1的时候算base,明显base=n-1,但是转成浮点再转回整数可能有问题,所以如果最后也没返回结果,默认返回保底的n-1
代码:
class Solution(object):
def smallestGoodBase(self, n):
"""
:type n: str
:rtype: str
"""
n = long(n)
import math
def good_base(n,k):
tmp = math.pow(n,1.0/k)
if abs(long(tmp)-tmp)<10**-6:
return long(tmp)-1
else:
return long(tmp)
def is_good_base(n,k):
if n%k!=1:
return False
if n==1:
return True
return is_good_base((n-1)/k,k)
now = int(math.ceil(math.log(n+1, 2)-1))
while now>=1:
base = good_base(n,now)
if is_good_base(n,base):
return str(base)
now = min(int(math.ceil(math.log(n*base+1, base+1)-1)), now-1)
return str(n-1)