题目
假如有一组字符串符合如下规律:
S
1
=
1
S
2
=
12
S
3
=
123
S
4
=
1234
…
S
9
=
123456789
S
10
=
12345678910
S
11
=
1234567891011
⋯
S
1
8
=
123456789101112131415161718
⋯
S _1 =1 \newline S _2=12 \newline S _3=123 \newline S _4 =1234 \newline \dots \newline S _9 =123456789 \newline S_{10} =12345678910 \newline S _{11} =1234567891011 \newline ⋯ \newline S _18 =123456789101112131415161718 \newline ⋯
S1=1S2=12S3=123S4=1234…S9=123456789S10=12345678910S11=1234567891011⋯S18=123456789101112131415161718⋯
(对于 S n S_n Sn来说,将从1到nn的数字拼接到一起)
现在我们把所有的字符串拼接起来,组成一个无限长的字符串 S = 1121231234 ⋯ 12345678910111213 ⋯ S = 1121231234 \cdots 12345678910111213\cdots S=1121231234⋯12345678910111213⋯ 你能找出该字符串的第nn位数字是多少吗?
输入
一个整数(1 < 整数 < 1 0 15 10^{15} 1015),表示所求的位数是多少位
输出
一个整数,表示该位上的数字是多少
输入样例
1
6
7
1234567
2345
234
输出样例
1
3
1
5
5
1
分析
- 首先分析每一行有多少个数字
分析表如下:
分段 | 数字个数 (i表示行号) |
---|---|
S 1 − S 9 S_1 -S_9 S1−S9 | i |
S 10 − S 99 S_{10} -S_{99} S10−S99 | 9+ (i -9)*2 |
S 100 − S 999 S_{100} -S_{999} S100−S999 | 9+ (99-9)*2+(i-99)*3 |
据此可推导出公式:
L
e
n
(
S
(
i
)
)
=
∑
w
=
1
w
=
l
e
n
(
i
)
−
1
w
{
(
1
0
w
−
1
)
−
(
1
0
w
−
1
−
1
)
}
+
∑
w
=
l
e
n
(
i
)
−
1
w
=
l
e
n
(
i
)
−
1
{
i
−
(
1
0
w
−
1
)
}
w
Len(S(i)) = \sum_{w=1}^{w=len(i)-1} w\{(10^w-1) -(10^{w-1}-1)\} + \sum_{w=len(i)-1}^{w=len(i)-1} \{ i-(10^w -1) \} w
Len(S(i))=w=1∑w=len(i)−1w{(10w−1)−(10w−1−1)}+w=len(i)−1∑w=len(i)−1{i−(10w−1)}w
可写作函数:
def lineLen(lineIndex):
# w表示 位数
w = len(str(lineIndex))
result = 0
for i in range(w):
t1 = '9'* (i+1)
t1 = int(t1)
if i == 0:
t2 = 0
else:
t2 = '9'*i
t2 = int(t2)
if i == w-1:
result += (lineIndex-t2) * (i+1)
else:
result += (t1-t2) * (i+1)
return result
现在我们可以使用函数lineLen(lineIndex)
求出任意行的长度
- 计算前n 行有多少个数字
分析可知, 该数列可以拆分位几个等差数列
等差数列求和公式为:
L n = a 1 n + n ( n − 1 ) 2 d L_n = a_1 n + \frac{n(n-1)}{2} d Ln=a1n+2n(n−1)d
分析表如下:
分段 | 前i行的总数 |
---|---|
L 1 − L 9 L_1 -L_9 L1−L9 | a 1 = 1 , n = i , d = 1 , L 1 ( i ) = a 1 n + n ( n − 1 ) 2 d a_1 = 1, n = i, d = 1, \newline L_1(i)= a_1 n + \frac{n(n-1)}{2} d a1=1,n=i,d=1,L1(i)=a1n+2n(n−1)d |
L 10 − L 99 L_{10} -L_{99} L10−L99 | a 1 = l i n e L e n ( 10 ) , n = i − 9 , d = 2 , L 2 ( i ) = L 1 ( 9 ) + a 1 n + n ( n − 1 ) 2 d a_1 = lineLen(10), n = i-9, d = 2, \newline L_2(i)= L_1(9)+a_1 n + \frac{n(n-1)}{2} d a1=lineLen(10),n=i−9,d=2,L2(i)=L1(9)+a1n+2n(n−1)d |
L 100 − L 999 L_{100} -L_{999} L100−L999 | a 1 = l i n e L e n ( 100 ) , n = i − 99 , d = 3 , L 3 ( i ) = L 1 ( 9 ) + L 2 ( 99 ) + a 1 n + n ( n − 1 ) 2 d a_1 = lineLen(100), n = i-99, d = 3, \newline L_3(i)= L_1(9)+L_2(99)+a_1 n + \frac{n(n-1)}{2} d a1=lineLen(100),n=i−99,d=3,L3(i)=L1(9)+L2(99)+a1n+2n(n−1)d |
代码如下:
# 计算前line行 有多少个数
def totalNum(line):
w = len(str(line))
seqstart = [0]*w
seqstart[0] = 1
for i in range(1,w):
seqstart[i] = lineLen(10**i)
resultsum = 0
for i in range(w):
if i==w-1:
n = line- (10**i -1)
else :
n = 9*(10**i)
a1 = seqstart[i]
d = i+1
resultsum += n*a1 + (n*(n-1)/2) *d
return int(resultsum)
- 查找, 需要查找:
- 第n个数字在第几行
- 找到行之后查找在改行的第几位
因为 S(i) 和L(i) 数列都是递增的,所以可以使用二分查找法.
代码如下:
# 使用二分查找,找到位置
def binaryFind(n,index,funcin):
start = 1
end = n+1
while start <= end:
mid = (start+end)//2
if funcin(mid) >= index and funcin(mid-1) < index :
return mid
elif funcin(mid) < index:
start = mid+1
else :
end = mid-1
return "not find "
全部代码
import sys
def lineLen(lineIndex):
# 公式: l(n) = 9 *1 + (99-9) *2 + ... + (n- 9...9)*i
# w表示 位数
w = len(str(lineIndex))
result = 0
for i in range(w):
t1 = '9'* (i+1)
t1 = int(t1)
if i == 0:
t2 = 0
else:
t2 = '9'*i
t2 = int(t2)
if i == w-1:
result += (lineIndex-t2) * (i+1)
else:
result += (t1-t2) * (i+1)
return result
# 使用二分查找,找到位置
def binaryFind(n,index,funcin):
start = 1
end = n+1
while start <= end:
mid = (start+end)//2
if funcin(mid) >= index and funcin(mid-1) < index :
return mid
elif funcin(mid) < index:
start = mid+1
else :
end = mid-1
return "not find "
# 计算前line行 有多少个数
def totalNum(line):
w = len(str(line))
seqstart = [0]*w
seqstart[0] = 1
for i in range(1,w):
seqstart[i] = lineLen(10**i)
resultsum = 0
for i in range(w):
if i==w-1:
n = line- (10**i -1)
else :
n = 9*(10**i)
a1 = seqstart[i]
d = i+1
resultsum += n*a1 + (n*(n-1)/2) *d
return int(resultsum)
def calculate(n):
line = binaryFind(n,n,totalNum)
index = n - totalNum(line-1)
# 此时要找的数字是 s(line) 的第index 个数字
if index < 10 :
return index
indexNum = binaryFind(line,index,lineLen)
index = index - lineLen(indexNum-1)
indexNum = str(indexNum)
return indexNum[index-1]
if __name__ == "__main__":
for line in sys.stdin:
line = line.strip()
if line == "":
continue
num = int(line)
result = calculate(num)
print(result)