我正在尝试解决USACO的算术级数问题。这是问题陈述。
算术级数是形式为a,a + b,a + 2b,...,a + nb的序列,其中n = 0、1、2、3,...。对于这个问题,a是一个非负整数,b是一个正整数。
编写一个程序,在双平方集S中找到所有长度为n的算术级数。双平方的集合定义为形式为p2 + q2的所有整数的集合(其中p和q为非负整数)。
输入的两行分别是n和m,它们分别是每个序列的长度,以及分别限制双平方搜索的上限。
我已经实现了一种可以正确解决该问题的算法,但是它花费的时间太长。在最大约束为n = 25和m = 250的情况下,我的程序在5秒的时间内没有解决问题。
代码如下:
n = 25
m = 250
bisq = set()
for i in range(m+1):
for j in range(i,m+1):
bisq.add(i**2+j**2)
seq = []
for b in range(1, max(bisq)):
for a in bisq:
x = a
for i in range(n):
if x not in bisq:
break
x += b
else:
seq.append((a,b))
程序输出正确的答案,但是花费的时间太长。我尝试以最大n / m值运行该程序,但30秒后,它仍在运行。
答案 0 :(得分:1)
免责声明:这不是一个完整的答案。这更多的是在哪里寻找的一般方向。
对于序列的每个成员,您正在寻找四个参数:两个要求平方和的数字(q_i
和p_i
),以及下一步要使用的两个差异( x
和y
)这样
q_i**2 + p_i**2 + b = (q_i + x)**2 + (p_i + y)
受制于:
0 <= q_i <= m
0 <= p_i <= m
0 <= q_i + x <= m
0 <= p_i + y <= m
未知数太多,因此我们无法获得封闭式解决方案。
b
:(仍然有很多未知数)q_i
,并声明它是序列的第一个成员。也就是说,让我们从q_1 = 0
开始搜索,尽可能扩展,然后提取所有长度为n
的序列。尽管如此,仍有太多未知数。x
:我们只有p_i
和y
可以解决。此时,请注意,满足方程式的可能值范围比0..m
的整个范围小得多。经过b = x*(2*q_i + x) + y*(2*p_i + y)
演算后,实际上没有太多要检查的值。最后一个修剪是它与完整搜索的区别所在。如果您明确记下此条件,则可以得到可能的p_i
值的范围,并从中找到步骤b
作为q_i
和{{1的函数}}。拒绝小于x
的序列应进一步简化搜索。
这应该使您从n
的复杂性转到〜O(m**4)
。进入时间限制应该足够了。
答案 1 :(得分:0)
还有其他一些事情可能会有助于缩小搜索空间:
b <= 2*m*m//n
a <= 2*m*m - b*n
对math.stackexchange的回答说,要使x成为双平方,则x的任何素数形式3 + 4k(例如3、7、11、19,...)必须具有均匀的力量我认为这意味着对于任何n> 3,b
必须是偶数。序列a
中的第一项是双平方,因此其偶数因子为3。如果b
为奇数,则a+1b
或a+2b
中的一个将为具有3的奇数个因数,因此不是双平方。