一群k男孩应该按照以下方式支付大理石:他们坐成一圈,每个男孩将比他右边的男孩更多地拿一块大理石,然后把剩下的大理石带到袋子里去他左边的男孩。
领导者首先为自己取出1块大理石。他将行李传递给他左边的那个男孩,然后他为自己移走了2个弹珠,并将行李传递到他的左边。然后那个男孩需要3个硬币并将袋子传递到他的左边,依此类推。这个过程一直持续到袋子为空(从袋子里取出的最后一个男孩可能没有那么多的弹珠)。
我想获得LEADER在整个过程中收到的弹珠总数。
这就是我所拥有的,它有效,但它太慢了:
def countMarbles(n, k):
c = 0
leader = 0
while n>0:
for i in range(k):
c+=1
if i == 0:
if c<=n:
leader += c
else:
leader += n
n -= c
return leader
答案 0 :(得分:3)
你正在施放的弹珠是1,然后是2,然后是3 ......
这种总和有一个公式,1到x的总和是(x)(x + 1) / 2
。
现在你被给予n,并想知道你可以制作多少次传球。这意味着获得最高x,使(x)(x + 1) / 2
低于或等于n。
我们可以通过解决0 = x^2 + x - 2n
来解决这个问题。我们可能会得到一个小数结果,所以我们应该取正则答案的最低值。
一旦我们找到了正确的x,我们就会知道包的每一个k通过,1到达领导者。他先获得1个大理石,然后获得k + 1弹珠,然后是2k + 1 ......
如果有x次通过,则x / k
的ceil前往领导者。取出始终为1的第一个传球,我们得到k系数大于0的l = ceil(x / k) - 1
次传球:((k + 1) + (2k + 1) + ... + (lk + 1)) = (1 + 2 + 3 + ... + l) * k + l = (l * (l + 1) / 2) * k + l.
考虑到领导者从1开始,解决方案是(l * (l + 1) / 2) * k + l + 1
唯一的问题是袋子里剩下的剩余大理石会发生什么。在那些应该成为领导者的情况下,我们还需要考虑它们。为了实现这一点,x必须是k的倍数,这意味着我们完成了这一轮,所以下一个应该是领导者,但是没有足够的弹珠再次通过。
这是一个python实现:
import math
def solve (n, k):
x = math.floor((-1 + math.sqrt(1 + 8*n)) / 2)
l = math.ceil(x / k) - 1
sol = (l * (l + 1) / 2) * k + l + 1
if x % k == 0 :
sol += n - (x * (x + 1) / 2)
return int(sol)