我在Topcoder中练习SRM问题。我遇到了这个问题
问题陈述:今天是平安夜。世界各地的人们 庆祝这个假期。以下故事发生在。的土地上 驯鹿,圣诞老人居住的地方。
驯鹿喜欢糖果。他们有n块糖果。的碎片 糖果编号为1到n。 Dasher是驯鹿之一。他 我想吃一个糖果。要选择他会吃的那个,Dasher 使用以下方法:虽然有多个 糖果:丢弃所有用完美方块编号的糖果(即 糖果1,4,9,16,25等)。重拍其余的糖果1 通过k,保持数字的顺序相同。曾经只有一件 糖果仍然存在,Dasher会吃掉它。
给你一个int n。您的方法必须计算并返回数字 最初分配给Dasher吃的那块糖果。
我使用ArrayList解决了这个问题但是我的解决方案因为非常大的数量而失败(Java Heap Sapce Exception)。因此我在考虑是否有可能解决O(1)空间复杂性中的问题。
请提出您的建议和方法。我不想要代码,请只解释解决这个问题的逻辑。
我已经重新打开了这个问题 问题陈述,因此Stackoverflow中的大师可以帮助我解决 O(1)空间复杂度
答案 0 :(得分:9)
另一种变体:
a = floor(sqrt(N-1))
b = min((N-1)/a, a+1)
solution = a*b+1
或者,换句话说,
unsigned long long eats(unsigned long long N) {
unsigned long long r = (unsigned long long)sqrt(N-1);
while(r*r >= N) --r;
while(r*(r+2) < N) ++r;
if (N <= r*(r+1)) {
return r*r+1;
}
return r*(r+1)+1;
}
证据来自于分析next
函数,该函数给出了任何糖果next(n*n) = 0
的下一个位置,因此它不是部分函数。如果a*a < N < (a+1)*(a+1)
,我们有next(N) = N - a
。因此,n = a*(a+1) + 1
形式的一些形式
a*(a+1)+1 -> a*a + 1 -> (a-1)*a + 1 -> ... -> 2*3 + 1 ->2*2 + 1 -> 1*2 + 1 -> 1*1 + 1 -> 0*1 + 1
我们也看到a*a +1
形式的数字也达到1.任何其他形式的数字在某个时刻达到大于1的正方形:
a*(a+1) -> a*a -> eliminated
a*(a+1) + r -> a*a + r -> (a-1)*a + r
代表2 <= r <= a
。如果r = a
,(a-1)*a + r = a*a
是正方形,则会立即消除。如果r < a
,则两个步骤后达到的数字具有相同的r
形式。接下来,数字达到
(r+1)*(r+2) + r -> (r+1)*(r+1) + r -> r*(r+1) + r -> r*r + r -> r*r -> elimination.
所以我们看到了
n*n + 1
或n*(n+1) + 1
到达以N
糖果开头的第一个地点的最后一个数字当然是不超过N
的最大数量。 QED。
答案 1 :(得分:5)
除非我犯了一个愚蠢的错误,否则有一个公式。它可能会被简化,但这是我遇到的第一个。
from math import floor, sqrt, ceil
def is_square(i):
sq = int(i**0.5)
return i == sq*sq
def brute(n):
seq = range(1, n+1)
while len(seq) > 1:
seq = [x for i,x in enumerate(seq, 1) if not is_square(i)]
return seq[0]
def dasher(n):
w = lambda i: floor(sqrt(4*i+1))-1
q = lambda i: ceil((i**2+3)/4)
return q(w(n-1)+1)
并检查:
>>> b = [brute(i) for i in range(1, 10**3)]
>>> d = [dasher(i) for i in range(1, 10**3)]
>>> b[:25]
[1, 2, 3, 3, 5, 5, 7, 7, 7, 10, 10, 10, 13, 13, 13, 13, 17, 17, 17, 17, 21, 21, 21, 21, 21]
>>> b == d
True
答案 2 :(得分:4)
我想我可能会在这里做点什么。
f(n) = 1 if n = 1
f(n) = f(n-floor(sqrt(n))) + floor(sqrt(n)) if n is not a perfect square
f(n) = f(n-1) if n is a perfect square
基本情况很清楚。 “完美正方形”的情况来自于观察,如果n是一个完美的正方形,当你消除完美的正方形时它将被消除,所以求解它相当于解决比它更小的一个,无论如何。最后一个来自观察到在移除地板(sqrt(n))完美正方形和重新编号后,你已经将一些数字向左移动(但是否则答案是相同的)。我们可以检查前几个案例......
n Answer f(n)
1 1 1
2 2 f(2-1) + 1 = f(1) + 1 = 1 + 1 = 2
3 3 f(3-1) + 1 = f(2) + 1 = 2 + 1 = 3
4 3 f(4-1) = f(3) = 3
5 5 f(5-2) + 2 = f(3) + 2 = 3 + 2 = 5
证明这一点,如果它是正确的,应该是一个简单的延伸,直到我完成它,我把它留作练习。您应该检查大量案例,看看它是否有效;如果它不起作用,我会删除它。
编辑:
我认为我注意到的趋势及其起作用的原因是,对于非平方n,答案永远不会小于n的最大平方。我认为这样做的原因是在删除小于或等于m ^ 2的所有内容之前,你永远不能删除m ^ 2 + 1。鉴于此,上述复发关系几乎是微不足道的。
答案 3 :(得分:0)
您知道最后一个号码将被特殊号码1删除。如果您生成的所有号码都被删除1,您将拥有一个包含特殊号码的号码。所以你要做的就是生成这些数字。
让我们看看是否有模式。
设n为150
数字被1删除
r = [1,2,3,5,7,10,13,17,21,26,31,37,43,50,57,65,73,82,91,101,111,122, 133]
r [i + 1] -r [i]
的数组[1,1,2,2,3,3,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11]
数字被2删除
r = [4,6,8,11,14,18,22,27,32,38,44,51,58,66,74,83,92,102,112,123,134,146]
r [i + 1] -r [i]
的数组[2,2,3,3,4,4,5,5,6,7,7,8,8,9,9,10,10,11,11,12]
数字被9删除 我们知道9中删除的数字在前2个元素中会有3个不同,第一个元素是9.从中我们可以生成在3,3,4,4,5这个模式后删除的数字,五 [9,12,15,19,23,28,33,39,45,52,59,67,75,84,93,103,113,124,135,147] [3,3,4,4,5,5,6,7,7,8,8,9,9,10,10,11,11,12]
import math
def getSpecial(n):
sp = list()
s = 1
while((s * s) <= n):
sp.append(s*s)
s += 1
return sp
def bruteForce(n):
nu = range(n+1)
nu.pop(0)
while(len(nu) > 1):
sp = getSpecial(len(nu))
removed = list()
for x in sp[::-1]:
removed.append(nu.pop(x-1))
return nu[0]
def fancyMathWitchCraft(n):
sp = getSpecial(n)
oneset = [1]
j = 0.0
while(oneset[-1] <= n):
oneset.append( oneset[-1] + int(1 + 1 * math.floor(j/2)) )
j = j + 1.0
if(oneset[-1] <= n):
return oneset[-1]
if(oneset[-2] <= n):
return oneset[-2]
if(oneset[-3] <= n):
return oneset[-3]
def main():
for x in range(1,2000):
if(bruteForce(x) != fancyMathWitchCraft(x)):
print(x, bruteForce(x), fancyMathWitchCraft(x))
print("Done")
if __name__ == "__main__":
main()
这背后的证据可能是最后一个完美的sq只会删除1个数字,所以最终的数字将来自最大的连续片段,它将在第一次迭代后不受影响,这将是最后一个分割。如果你真的想要一个数学证明,你必须把这个问题带到meta.stackoverflow
答案 4 :(得分:-1)
n=1, eats=1
n=2, eats=2
n=3, eats=3
n=4, eats=3
n=5, eats=5
...
你看到一种模式出现了吗?提出一个公式,并使用mathematical induction
证明公式是正确的这是c ++代码:
#include <iostream>
#include <cmath>
using namespace std;
bool is_perfect_square(int value)
{
return pow( static_cast<double>(static_cast<int>(sqrt(static_cast<double>(value)))), 2.0) == value;
}
int EatEm(int n)
{
while (is_perfect_square(n))
{
n -= (static_cast<int>(sqrt(static_cast<double>(n)) - 1));
}
return n;
}
int main()
{
int res = EatEm(25);
cout << res << endl;
return 0;
}