我想解决其中二次项的递归关系。
例如.. T(n)= T(n-1)^2 + T(n-1) + 2
是一个递归关系,我必须打印其总和模块100000.
如果不使用简单的强力方法,我该怎么做?
答案 0 :(得分:3)
取决于n
的大小(例如,大约10,000,000),您可能会在一小段时间(例如大约一秒钟)内运行一个简单的for
循环。
我无法判断您是否可以找到通用T(1)
和/或通用递归的数学公式,但我的猜测是您不能。不过,我可以告诉你一个可以帮助你解决问题的数学属性。它被称为congruence。简而言之,这就是语法:
a =(15)= b
表示15分为b - a
。实际的数学符号是=
,有三行,数字写在它上面,但我不能真正输入它!
现在这里有几个对你有用的定理:
1
a =(n)= b \
> => a =(n)= c
b =(n)= c /
2
a =(n)= b => a+c =(n)= b+c
3
a =(n)= b => a*c =(n)= b*c
4
a =(n)= b => a^2 =(n)= b^2
通过将a
和b
写为:
a = k1*n+r
b = k2*n+r
并应用转换并确保最后b - a
仍可被n
整除。
那就是说,你的算法如下(假设你想要T1到TN mod M之和):
T = 3 /* initial T1 */
TSum = T /* initial sum */
for i=1 to N
T = (T^2 % M + T + 2) % M
TSum = (TSum + T) % M
这里要注意的重要一点是,T
和TSum
总是由M
限定,最大中间结果来自表达式T^2
(对于非平凡的M
s),最多可以(M-1)^2
。
因此,在您的实现中,您实际上不需要处理非常大的数字,而只需要使用足以容纳(M-1)^2
的数据类型。在C中,uint64_t
会这样做。请注意,对于M=100000
,(M-1)^2
不适合32位整数。
顺便说一下,这个算法是O(N)
,所以除非N
非常大或除非它在一个非常频繁的循环中,否则它应该足够快以满足您的日常需求!
修改强>
问题实际上可以在O(M)
而不是O(N)
中解决。这是因为所有T(i)
都在[0, M-1)
范围内,因此计算到T(M+1)
,您肯定会回头。由于T(n)
完全取决于T(n-1)
,因此获取T(n-1)
的重复值将导致与第一次相同的值链。
因此,让我们展开T
和TSum
,以便更好地了解这是如何被利用的。假设T
生成值A
,B
,...,Z
,在Z
之后,它会循环回K
并在一对夫妇之后它在P
完成的周期(因为我们达到了N
):
T A B C D E ... K ... Z K ... Z K ... Z ... K ... P
TSum AS BS CS DS ES ... KS ... ZS KS2 ... ZS2 KS3 ... ZS3 ... KSt ... PSt
所以你的目标是计算PSt
。我们的想法是计算最多KS2
,将其与KS
区分开来,将其乘以t
并将其添加到KS
以获得KSt
。然后添加剩余部分以获取PSt
。
算法如下:
Sums=[M times 0] /* initially, no sum is calculated */
Indices=[M times 0] /* Indices[i] = I means Sums[i] corresponds to T(1)+...+T(I) */
T = 3 /* initial T1 */
TSum = T /* initial sum */
Sums[T] = TSum
Indices[T] = 1
for i=2 to N
T = (T^2 % M + T + 2) % M
if Sums[T] != 0 /* a loop is detected */
break
TSum = (TSum + T) % M
Sums[T] = TSum
Indices[T] = i
if i == N
return TSum
/* compute how many cycles */
cycle_length = i - Indices[T]
t = (N - Indices[T]) / cycle_length
/* add sum of the cycles immediately */
TSum = (Sums[T] + t * (TSum - Sums[T])) % M
/* add what is left */
for i=Indices[T] + t * cycle_length+1 to N
T = (T^2 % M + T + 2) % M
TSum = (TSum + T) % M
注意:索引计算中可能存在逐个错误。如果您打算使用此算法,请仔细检查以确保它不会遗漏任何T(i)
或将其加总两次。
答案 1 :(得分:2)
这是一种更加数学化的方法来解决递归方程,例如使用z变换或生成函数。对所讨论的方程进行z变换,然后找到f(z)生成多项式用于递推,并采用逆z变换得到闭合空间函数。
<强>步骤:强>
答案 2 :(得分:0)
这实际上更像是一个数学问题,但无论如何,这里有一些你应该考虑的事情:
如果您只对总和100,000 100,000感兴趣,则可以执行所有计算模式100,000。 (如果你不知道为什么这是真的,不要尝试在作业答案中使用它。但那当然是一个数学问题。)
你有一阶递归方程(你的标题是错的,顺便说一下),真的应该不是通过递归来实现它,而是迭代地实现它。
粗糙的伪代码(希望你能从中吸取教训,不只是把它作为功课,但是再一次,你唯一受伤的就是你自己):
value = 3 // T(1)
sum = value
N.times do
value = (value^2 + value + 2) % 100000
sum = (sum + value) % 100000
end
对于更加面向数学的答案,您还可以考虑如何获得和S(n)的递归公式,然后为此计算闭合形式的解。