计算几何级数之和(mod m)

时间:2009-10-05 22:53:48

标签: number-theory

我有一个系列

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。) 所以请给我一个有效的算法来找到总和。

4 个答案:

答案 0 :(得分:11)

这是我遇到的类似问题的算法

您可能知道可以用对数时间计算数字的幂。您也可以这样计算几何系列的总和。因为它持有

1 + a + a^2 + ... + a^(2*n+1) = (1 + a) * (1 + (a^2) + (a^2)^2 + ... + (a^2)^n),

你可以递归计算右边的几何系列来得到结果。

这样你就不需要除法,所以你可以将所有和(以及中间结果)的余数取模为你想要的任何数字。

答案 1 :(得分:8)

正如您所指出的那样,对任意模数m进行计算很困难,因为许多值可能没有乘法逆模m。但是,如果您可以通过精心选择的备用模组来解决它,则可以将它们组合起来以获得解决方案模块。

将因子m分解为p_1, p_2, p_3 ... p_n,使每个p_i是不同素数的力量

由于每个p是不同的主要幂,它们是成对互质的。如果我们可以计算关于每个模数p_i的系列之和,我们可以使用Chinese Remainder Theorem将它们重新组合成解决方案模型。

对于每个主要功率模数,有两个微不足道的特殊情况:

如果i ^ m与0 mod p_i一致,则总和平均为0.

如果i ^ m与1 mod p_i一致,则总和与k mod p_i一致。

对于其他值,可以将常用公式应用于几何序列的总和:

S = sum(j = 0到k,(i ^ m)^ j)=((i ^ m)^(k + 1) - 1)/(i ^ m - 1)

TODO:证明(i ^ m - 1)是p_i的互质,或者找到他们有一个非平凡的GCD的替代解决方案。希望p_i是一个主要的权力,也是m的除数这一事实将有一些用处...如果p_i是我的除数。条件成立。如果p_i是素数(而不是素数幂),则应用特殊情况i ^ m = 1,或者(i ^ m - 1)具有乘法逆。

如果几何和公式不适用于某些p_i,则可以重新排列计算,因此您只需要从1迭代到p_i而不是1到k,这样可以利用这一事实条款重复的期限不超过p_i

(由于你的系列不包含j = 0项,你想要的值实际上是S-1。)

这产生一组同余mod p_i,它满足CRT的要求。 在上面的链接中描述了将它们组合成解决方案的过程,所以我在此不再重复。

答案 2 :(得分:2)

基于@braindoper的方法计算

的完整算法
1 + a + a^2 + ... +a^n mod m

在Mathematica中看起来像这样:

geometricSeriesMod[a_, n_, m_] := 
   Module[ {q = a, exp = n, factor = 1, sum = 0, temp},

   While[And[exp > 0, q != 0],
     If[EvenQ[exp],
       temp = Mod[factor*PowerMod[q, exp, m], m];
       sum = Mod[sum + temp, m];
       exp--];
     factor = Mod[Mod[1 + q, m]*factor, m];
     q = Mod[q*q, m];
     exp = Floor[ exp /2];
   ];

   Return [Mod[sum + factor, m]]
]

参数:

  • a是该系列的“比例”。它可以是任何整数(包括零和负值)。
  • n是该系列的最高指数。允许的是整数&gt; = 0。
  • m是整数模数!= 0

注意:算法在每次算术运算后执行Mod运算。如果您将此算法转录为整数有限字长的语言,这一点至关重要。

答案 3 :(得分:2)

如果您考虑O(log(k))变量,可以通过repeated squaring, O(log(k)log(m))时间或m时间的方法来完成。

通常,a[n]=1+b+b^2+... b^(n-1) mod m可以通过注意:

来计算
  1. a[j+k]==b^{j}a[k]+a[j]
  2. a[2n]==(b^n+1)a[n]
  3. 第二个只是第一个的推论。

    在您的情况下,b=i^m可以在O(log m)时间内计算。

    以下Python代码实现了这一点:

    def geometric(n,b,m):
        T=1
        e=b%m
        total = 0
        while n>0:
            if n&1==1:
                total = (e*total + T)%m
            T = ((e+1)*T)%m
            e = (e*e)%m
            n = n/2
            //print '{} {} {}'.format(total,T,e)
        return total
    

    这一点魔法有一个数学原因 - 对的操作定义为

    (a,r)@(b,s)=(ab,as+r)
    

    是关联的,规则1基本上意味着:

    (b,1)@(b,1)@... n times ... @(b,1)=(b^n,1+b+b^2+...+b^(n-1))
    

    当操作关联时,重复平方始终有效。在这种情况下,@运算符的时间为O(log(m)),因此重复平方需要O(log(n)log(m))

    查看此问题的一种方法是矩阵求幂:

    [[b,1],[0,1]]^n == [[b^n,1+b+...+b^(n-1))],[0,1]]
    

    您可以使用类似的方法来计算(a^n-b^n)/(a-b) modulo m,因为矩阵取幂会给出:

    [[b,1],[0,a]]^n == [[b^n,a^(n-1)+a^(n-2)b+...+ab^(n-2)+b^(n-1)],[0,a^n]]