我有一个系列
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。) 所以请给我一个有效的算法来找到总和。
答案 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
可以通过注意:
a[j+k]==b^{j}a[k]+a[j]
a[2n]==(b^n+1)a[n]
第二个只是第一个的推论。
在您的情况下,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]]