我不知道他们如何期望一个没有背景的随机程序员从中找出答案。
但这里是模运算的简要介绍,应该使这成为可能。
在编程中,n % k 是模运算符。它指的是取n / k的剩余部分。它满足以下两个重要属性:
(n + m) % k = ((n % k) + (m % k)) % k
(n * m) % k = ((n % k) * (m % k)) % k
正因为如此,对于任何k,我们可以认为所有具有相同余数的数字在某种程度上是相同的。结果是所谓的“整数模 k”。它满足您习惯的大部分代数规则。你有结合性、交换性、分配律、0 加法和 1 乘法。
但是,如果 k 是像 10 这样的合数,那么不幸的是 2 * 5 = 10 表示对 10、2 * 5 = 0 取模。这对除法来说是个问题。
但是如果 k = p 是质数,那么事情就会变得容易得多。如果 (a*m) % p = (b*m) % p 那么 ((a-b) * m) % p = 0 所以 (a-b) * m 可以被 p 整除。因此 (a-b) 或 m 可以被 p 整除。
对于任何非零余数m,让我们看一下序列m % p, m^2 % p, m^3 % p, ...。这个序列无限长,只能取p值。所以我们必须重复a < b和m^a % p = m^b %p。所以(1 * m^a) % p = (m^(b-a) * m^a) % p。由于 m 不除 p,m^a 也不除,因此 m^(b-a) % p = 1。此外,m^(b-a-1) % p 的行为与m^(-1) = 1/m 一样。 (如果你有足够的数学,你会发现乘法下的非零余数是一个有限群,所有的余数组成一个域。但我们忽略它。)
(我将在所有地方删除 % p。假设它在任何计算中都存在。)
现在让a 成为满足m^a = 1 的最小正数。然后1, m, m^2, ..., m^(a-1)形成一个长度为a的循环。对于1, ..., p-1中的任何n,我们可以形成一个循环(可能相同,可能不同)n, n*m, n*m^2, ..., n*m^(a-1)。可以看出,这些循环分区1, 2, ..., p-1,其中每个数字都在一个循环中,每个循环的长度为a。因此,a 划分p-1。作为旁注,由于a除p-1,我们很容易得到Fermat's little theorem,m^(p-1)有余数1,因此m^p = m。
好的,足够的理论。现在解决你的问题。假设我们有一个基地b = 10^i。他们正在讨论的素数测试是 a_0 + a_1 * b + a_2 * b^2 + a_k * b^k 可以被素数 p 整除当且仅当 a_0 + a_1 + ... + a_k 可以被 p 整除。查看(p-1) + b,这只有在b % p为1时才会发生。如果b % p为1,则在模运算中b的任意幂为1,并且测试有效。
所以我们正在寻找最小的i使得10^i % p是1。从我上面显示的,i 总是存在的,并且划分p-1。所以你只需要分解p-1,然后尝试10的每个幂,直到找到最小的i有效。
请注意,您应该在每一步都% p,以防止这些权力变得太大。通过重复平方可以加快计算速度。因此,例如,可以通过依次计算以下各项来计算10^20 % p。
10 % p
10^2 % p
10^4 % p
10^5 % p
10^10 % p
10^20 % p