计算几何级数之和 (mod m)
我有一个系列,
S = i^(m) + i^(2m) + ............... + i^(km) (mod m)
0 <= i < m, k may be very large (up to 100,000,000), m <= 300000
我想求总和。我无法应用几何级数(GP)公式,因为结果将具有分母,然后我将必须找到可能不存在的模逆(如果分母和 m 不是互质)。
所以我做了一个替代算法,假设这些幂将使一个周期的长度远小于 k (因为它是一个模方程,所以我会得到类似 2,7,9,1,2,7,9, 1....) 并且该循环将在上述系列中重复。因此,我不会从 0 迭代到 k,而是只求一个循环中的数字之和,然后计算上述系列中的循环数并将它们相乘。所以我首先找到了i^m (mod m)
,然后一次又一次地乘以这个数字,并在每一步取模,直到再次到达第一个元素。
但是当我实际编写算法时,对于 i 的某些值,我得到了非常大的循环。因此在终止之前花费了大量时间,因此我的假设是不正确的。
那么我们还能发现其他模式吗? (基本上我不想迭代 k。) 所以请给我一个求和的有效算法的想法。
I have a series
S = i^(m) + i^(2m) + ............... + i^(km) (mod m)
0 <= i < m, k may be very large (up to 100,000,000), m <= 300000
I want to find the sum. I cannot apply the Geometric Progression (GP) formula because then result will have denominator and then I will have to find modular inverse which may not exist (if the denominator and m are not coprime).
So I made an alternate algorithm making an assumption that these powers will make a cycle of length much smaller than k (because it is a modular equation and so I would obtain something like 2,7,9,1,2,7,9,1....) and that cycle will repeat in the above series. So instead of iterating from 0 to k, I would just find the sum of numbers in a cycle and then calculate the number of cycles in the above series and multiply them. So I first found i^m (mod m)
and then multiplied this number again and again taking modulo at each step until I reached the first element again.
But when I actually coded the algorithm, for some values of i, I got cycles which were of very large size. And hence took a large amount of time before terminating and hence my assumption is incorrect.
So is there any other pattern we can find out? (Basically I don't want to iterate over k.)
So please give me an idea of an efficient algorithm to find the sum.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是我遇到的类似问题的算法
您可能知道可以在对数时间内计算一个数字的幂。您也可以这样做来计算几何级数的总和。因为它认为
可以递归计算右手上的几何级数来得到结果。
这样您就不需要除法,因此您可以将总和(以及中间结果)的余数对您想要的任何数字取模。
This is the algorithm for a similar problem I encountered
You probably know that one can calculate the power of a number in logarithmic time. You can also do so for calculating the sum of the geometric series. Since it holds that
you can recursively calculate the geometric series on the right hand to get the result.
This way you do not need division, so you can take the remainder of the sum (and of intermediate results) modulo any number you want.
正如您所指出的,计算任意模 m 很困难,因为许多值可能没有乘法逆模 m。但是,如果您可以求解一组精心选择的替代模数,则可以将它们组合起来以获得模 m 的解。
将 m 分解为
p_1, p_2, p_3 ... p_n
,使得每个p_i
都是不同素数的幂由于每个 p 都是不同素数的幂,因此它们是成对互质的。如果我们可以计算关于每个模数 p_i 的级数之和,我们可以使用中国剩余定理 将它们重新组装成 mod m 的解。
对于每个质数幂模,有两个简单的特殊情况:
如果 i^m 同余 0 mod
p_i
,则总和为 0。如果 i^m 同余 1 mod
p_i
,那么总和等于 k modp_i
。对于其他值,可以应用几何数列之和的常用公式:
S = sum(j=0 to k, (i^m)^j) = ((i^m)^(k+1) - 1) / (i^m - 1)
TODO:证明 (i^m - 1) 与
p_i
互质,或者当它们具有非平凡的 GCD 时找到替代解决方案。希望p_i
是素数幂并且也是 m 的约数这一事实会有一些用处......如果p_i
是 i 的约数。条件成立。如果 p_i 是素数(与素数幂相对),则适用特殊情况 i^m = 1,或者 (i^m - 1) 具有乘法逆元。如果几何和公式不适用于某些
p_i
,您可以重新安排计算,这样您只需从 1 迭代到p_i
而不是 1 到 k,从而利用事实上,这些术语的重复周期不超过p_i
。(由于您的级数不包含 aj=0 项,因此您想要的值实际上是 S-1。)
这会产生一组同余 mod
p_i
,满足 CRT 的要求。将它们组合成一个解 mod m 的过程在上面的链接中有描述,所以这里不再重复。
As you've noted, doing the calculation for an arbitrary modulus m is difficult because many values might not have a multiplicative inverse mod m. However, if you can solve it for a carefully selected set of alternate moduli, you can combine them to obtain a solution mod m.
Factor m into
p_1, p_2, p_3 ... p_n
such that eachp_i
is a power of a distinct primeSince each p is a distinct prime power, they are pairwise coprime. If we can calculate the sum of the series with respect to each modulus p_i, we can use the Chinese Remainder Theorem to reassemble them into a solution mod m.
For each prime power modulus, there are two trivial special cases:
If i^m is congruent to 0 mod
p_i
, the sum is trivially 0.If i^m is congruent to 1 mod
p_i
, then the sum is congruent to k modp_i
.For other values, one can apply the usual formula for the sum of a geometric sequence:
S = sum(j=0 to k, (i^m)^j) = ((i^m)^(k+1) - 1) / (i^m - 1)
TODO: Prove that (i^m - 1) is coprime to
p_i
or find an alternate solution for when they have a nontrivial GCD. Hopefully the fact thatp_i
is a prime power and also a divisor of m will be of some use... Ifp_i
is a divisor of i. the condition holds. Ifp_i
is prime (as opposed to a prime power), then either the special case i^m = 1 applies, or (i^m - 1) has a multiplicative inverse.If the geometric sum formula isn't usable for some
p_i
, you could rearrange the calculation so you only need to iterate from 1 top_i
instead of 1 to k, taking advantage of the fact that the terms repeat with a period no longer thanp_i
.(Since your series doesn't contain a j=0 term, the value you want is actually S-1.)
This yields a set of congruences mod
p_i
, which satisfy the requirements of the CRT.The procedure for combining them into a solution mod m is described in the above link, so I won't repeat it here.
这可以通过重复平方的方法来完成,即
O(log( k))
时间,或O(log(k)log(m))
时间(如果您将m
视为变量)。一般来说,a[n]=1+b+b^2+... b^(n-1) mod m 可以通过以下方式计算:
a[2n]==(b^n+1)a[n]
第二个是第一个推论。
在您的情况下,可以在
O(log m)
时间内计算出b=i^m
。下面的 Python 代码实现了这一点:
这个魔法有一个数学原因 - 定义为结合的对的运算
,规则 1 基本上意味着:
当运算具有结合性时,重复平方总是有效。在本例中,@ 运算符的时间为 O(log(m)),因此重复平方需要 O(log(n)log(m))< /代码>。
看待这个问题的一种方法是矩阵求幂:
您可以使用类似的方法来计算
(a^nb^n)/(ab)
模m
因为矩阵求幂给出:This can be done via the method of repeated squaring, which is
O(log(k))
time, orO(log(k)log(m))
time, if you considerm
a variable.In general,
a[n]=1+b+b^2+... b^(n-1) mod m
can be computed by noting that:a[j+k]==b^{j}a[k]+a[j]
a[2n]==(b^n+1)a[n]
The second just being the corollary for the first.
In your case,
b=i^m
can be computed inO(log m)
time.The following Python code implements this:
This bit of magic has a mathematical reason - the operation on pairs defined as
is associative, and the rule 1 basically means that:
Repeated squaring always works when operations are associative. In this case, the
@
operator isO(log(m))
time, so repeated squaring takesO(log(n)log(m))
.One way to look at this is that the matrix exponentiation:
You can use a similar method to compute
(a^n-b^n)/(a-b)
modulom
because matrix exponentiation gives:基于 @braindoper 的方法,
在 Mathematica 中计算的完整算法如下所示:
参数:
a
是级数的“比率”。它可以是任何整数(包括零和负值)。n
是该级数的最高指数。允许的整数 >= 0。m
是整数模 != 0注意:算法在每个算术运算后执行 Mod 运算。如果您将此算法转录为整数字长有限的语言,这一点至关重要。
Based on the approach of @braindoper a complete algorithm which calculates
looks like this in Mathematica:
Parameters:
a
is the "ratio" of the series. It can be any integer (including zero and negative values).n
is the highest exponent of the series. Allowed are integers >= 0.m
is the integer modulus != 0Note: The algorithm performs a Mod operation after every arithmetic operation. This is essential, if you transcribe this algorithm to a language with a limited word length for integers.