Tal*_*iss 13 python puzzle math
我买了一张空白的DVD来录制我最喜欢的电视节目.它带有20位数的贴纸.每个'0' - '9'中的2个.
我认为用数字标记我的新DVD收藏品是个好主意.我在录制的第一张DVD上贴了"1"标签,将19个剩余的贴纸放在抽屉里.
第二天,我买了另一张空白DVD(用它收到20张新贴纸),在录制完这个节目之后,我将它标记为"2".
然后我开始疑惑:贴纸什么时候会用完,我将无法再贴上DVD标签了?
几行Python,不是吗?
你能提供能够在合理的运行时间内解决这个问题的代码吗?
编辑:蛮力只需要太长时间才能运行.请改进您的算法,以便您的代码在一分钟内返回正确答案?
额外的功劳:如果DVD附带3个贴纸的每个数字怎么办?
这是一个旧的解决方案,全新的6百万倍的解决方案在底部.
解:
time { python solution.py; }
0: 0
1: 199990
2: 1999919999999980
3: 19999199999999919999999970
4: 199991999999999199999999919999999960
5: 1999919999999991999999999199999999919999999950
6: 19999199999999919999999991999999999199999999919999999940
7: 199991999999999199999999919999999991999999999199999999919999999930
8: 1999919999999991999999999199999999919999999991999999999199999999919999999920
9: 19999199999999919999999991999999999199999999919999999991999999999199999999919999999918
real 1m53.493s
user 1m53.183s
sys 0m0.036s
Run Code Online (Sandbox Code Playgroud)
码:
OPTIMIZE_1 = True # we assum that '1' will run out first (It's easy to prove anyway)
if OPTIMIZE_1:
NUMBERS = [1]
else:
NUMBERS = range(10)
def how_many_have(dight, n, stickers):
return stickers * n
cache = {}
def how_many_used(dight, n):
if (dight, n) in cache:
return cache[(dight,n)]
result = 0
if dight == "0":
if OPTIMIZE_1:
return 0
else:
assert(False)
#TODO
else:
if int(n) >= 10:
if n[0] == dight:
result += int(n[1:]) + 1
result += how_many_used(dight, str(int(n[1:])))
result += how_many_used(dight, str(int(str(int(n[0])-1) + "9"*(len(n) - 1))))
else:
result += 1 if n >= dight else 0
if n.endswith("9" * (len(n)-4)): # '4' constant was pick out based on preformence tests
cache[(dight, n)] = result
return result
def best_jump(i, stickers_left):
no_of_dights = len(str(i))
return max(1, min(
stickers_left / no_of_dights,
10 ** no_of_dights - i - 1,
))
def solve(stickers):
i = 0
stickers_left = 0
while stickers_left >= 0:
i += best_jump(i, stickers_left)
stickers_left = min(map(
lambda x: how_many_have(x, i, stickers) - how_many_used(str(x), str(i)),
NUMBERS
))
return i - 1
for stickers in range(10):
print '%d: %d' % (stickers, solve(stickers))
Run Code Online (Sandbox Code Playgroud)
证明'1'将首先耗尽:
def(number, position):
""" when number[position] is const, this function is injection """
if number[position] > "1":
return (position, number[:position]+"1"+number[position+1:])
else:
return (position, str(int(number[:position])-1)+"1"+number[position+1:])
Run Code Online (Sandbox Code Playgroud)
这证明存在一个解决方案:
假设你得到21位数字,你将开始丢失你购买的每张DVD和标签((+20) + (-21))的贴纸.
在此之前你积累了多少贴纸并不重要.从这里开始,你的贴纸藏品全部下坡,你最终会用完.
全新的解决方案。比第一个快 6 亿倍。
time { python clean.py ; }
0: 0
1: 199990
2: 1999919999999980
3: 19999199999999919999999970
4: 199991999999999199999999919999999960
5: 1999919999999991999999999199999999919999999950
6: 19999199999999919999999991999999999199999999919999999940
7: 199991999999999199999999919999999991999999999199999999919999999930
8: 1999919999999991999999999199999999919999999991999999999199999999919999999920
9: 19999199999999919999999991999999999199999999919999999991999999999199999999919999999918
real 0m0.777s
user 0m0.772s
sys 0m0.004s
Run Code Online (Sandbox Code Playgroud)
代码:
cache = {}
def how_many_used(n):
if n in cache:
return cache[n]
result = 0
if int(n) >= 10:
if n[0] == '1':
result += int(n[1:]) + 1
result += how_many_used(str(int(n[1:])))
result += how_many_used(str(int(str(int(n[0])-1) + "9"*(len(n) - 1))))
else:
result += 1 if n >= '1' else 0
if n.endswith("9" * (len(n)-0)) or n.endswith("0" * (len(n)-1)):
cache[n] = result
return result
def how_many_have(i, stickers):
return int(i) * stickers
def end_state(i, stickers):
if i == '':
return 0
return how_many_have(i, stickers) - how_many_used(i)
cache2 = {}
def lowest_state(i, stickers):
if stickers <= 0:
return end_state(i, stickers)
if i in ('', '0'):
return 0
if (i, stickers) in cache2:
return cache2[(i, stickers)]
lowest_candidats = []
tail9 = '9' * (len(i)-1)
if i[0] == '1':
tail = str(int('0'+i[1:]))
lowest_candidats.append(end_state(str(10**(len(i) - 1)), stickers))
lowest_candidats.append(lowest_state(tail, stickers - 1) + end_state(str(10**(len(i) - 1)), stickers))
else:
tail = str(int(i[0])-1) + tail9
series = end_state(tail9, stickers)
if series < 0:
lowest_candidats.append(lowest_state(str(int('0'+i[1:])), stickers) + end_state(i[0] + '0'*(len(i)-1), stickers))
lowest_candidats.append(lowest_state(tail, stickers))
result = min(lowest_candidats)
cache2[(i, stickers)] = result
return result
def solve(stickers):
i=1
while lowest_state(str(i), stickers) >= 0:
i *= 2
top = i
bottom = 0
center = 0
while top - bottom > 1:
center = (top + bottom) / 2
if lowest_state(str(center), stickers) >= 0:
bottom = center
else:
top = center
if lowest_state(str(top), stickers) >= 0:
return top
else:
return bottom
import sys
sys.setrecursionlimit(sys.getrecursionlimit() * 10)
for i in xrange(10):
print "%d: %d" % (i, solve(i))
Run Code Online (Sandbox Code Playgroud)