如果一个数字的数字从最高有效数字开始形成一个非递减序列,我们就称它为平滑数字。按升序对所有这些数字进行排序,并为每个数字分配一个数字。需要输出第N个平滑数N。
1 <= N <= 2147483647
例子:
Ввод: 3 Вывод: 3
Ввод: 11 Вывод: 12
我用 Python 写了这段代码:
n = int(input())
result = ""
#В dp[i][j] записано кол-во гладких чисел длины i, начинающихся на цифру j
dp = [[0] * 10 for _ in range(n + 1)] #я немного не понял, откуда надо брать длину dp
for j in range(10):
dp[1][j] = 1
for i in range(2, n):
for j in range(10):
dp[i][j] = sum(dp[i - 1][k] for k in range(10) if k >= j)
#Находим длину n-го гладкого числа
n_l = 1
for i in range(1, n):
if dp[i + 1][0] >= n and dp[i][0] < n:
n_l = i
break
n -= dp[n_l][0]
#Находим первую цифру числа
j = 1
while n >= dp[n_l][j]:
n -= dp[n_l][j]
j += 1
result += str(j)
prev = j
#Находим оставшиеся цифры числа
if n_l > 1:
while n > 0:
for j in range(prev + 1, 10):
if n <= dp[i - 1][j]:
n -= dp[i - 1][j]
result += str(j)
prev = j
break
n -= dp[n_l - 1][j]
print(result)
此代码仅适用于 N 的小值。我应该在其中修复什么以便它适用于 N 的大值(N <= 2147483647)
例子:
如果
f(k, d)
是位数d
中带位数的平滑数的个数k
,则f(k, d) = sum(d <= e < 10, f(k - 1, e))
. 边界条件f(1, d) = 1
。然后
f
通过以下代码计算函数:使用该功能
f
,您可以从数字中“收集”n
第 - 个数字。计算代码m
- 答案中的位数:第 th 个数字
n
的数字是从最高有效数字到最年轻的数字中选择的。d
- 最后匹配的数字,k - 数字:一起:
添加
函数
f(k, d)
结果等于Cnk(k + 8 - d, 9 - d)
。在之前的实现中,函数f
可以替换为 ......并且会跑得更快。这个事实的证明并不难,我暂时省略它。我希望直接评估
Cnk
会使 C++ 实现更简单、更短,但我错了。用 values 填充数组更容易f
:通常可以达到以下数量
18348006354228436599 = Cnk(577, 9) - 1
:评论建议生成平滑的数字。
我想出了这个选项:
但是运行太慢了