这比我想象的要复杂,但我认为我已经想出了最简单情况(k=2)的解决方案。
首先,我尝试通过提出以下问题来简化:序列中哪个位置有数字10^i * k
(其中i = 1, 2, 3, ...
)?对于k = 2,这些数字是20、200、2000,...
i k n
1 2 20/2 = 10
2 2 200/2 + 2* 5 = 110
3 2 2000/2 + 2* 50 + 18* 5 = 1190
4 2 20000/2 + 2*500 + 18*50 + 162*5 = 12710
i 2 10^i + 2*10^(i-1)/2 + 18*10^(i-2)/2 + 162*10^(i-3)/2 + ?*10^(i-4)/2 + ...
在最后一行,我试图表达这个模式。第一部分是可被2整除的数字。然后还有i-1个附加部分,用于首位为2、第二位以此类推的奇数。困难的部分是计算因子(2,18,162等)。
下面是一个函数,返回任何i所需的新因子:
f(i) = 2 * 10^(i-2) - sum(10^(i-x-1)*f(x), x from 2 to i-1) = 2 * 9^(i-2) [thx @m69]
f(2) = 2
f(3) = 2*10 - (1*2) = 18
f(4) = 2*100 - (10*2 + 1*18) = 162
f(5) = 2*1000 - (100*2 + 10*18 + 1*162) = 1458
因此,我们可以使用以下算法:
找到不超过位置的最高数字10^i*2
。(如果n
在范围[positionOf(10^i*2), positionOf(10^i*2) + (10^i)]
内,则我们已经知道解决方案:10^i*2 + (n - positionOf(10^i*2))
。例如,如果我们发现i=2,我们知道下一个100个值都在序列中:[201, 300],所以如果110 <= n <= 210,则解决方案为200+(n-110) = n+90。)
int nn = positionOf(10^i * 2);
int s = 10^i * 2;
for (int ii = i; ii >= 0; ii--) {
for (int j = 1; j < 10; j++) {
if (j == 1 || j == 6) {
if (n <= nn + 10^ii)
return s + nn - n;
nn += 10^ii;
s += 10^ii;
int tmp = positionOf(10^ii);
if (nn + tmp > n)
break;
nn += tmp;
s += 10^ii;
} else {
int tmp = positionOf(10^ii * 2);
if (nn + tmp > n)
break;
nn += tmp;
s += 10^ii * 2;
}
}
}
return s;
这只是未经测试的不完整的伪代码(我知道在Java中不能使用^
),ii = 1或0需要被视为特殊情况,这个缺失以及如何找到i
也没有显示,否则答案会变得太长。