信息学竞赛中计算结果对 $10^9+7$ 取余数的原因

大家在学习信息学竞赛的过程中,总是会遇到要求计算结果对 (10^9+7) 或者 (10007) 这样的数取余数的结果,比如:http://codeforces.com/problemset/problem/1423/J

链接中的题目中就有一句话:

For each test case (i), print the answer on separate lines: number of polynomials (P) as described in statement such that (P(2)=m_i), modulo (10^9+7).

那么为什么要对 (10^9+7) 呢?

最主要的原因是一些运算的结果会很大,如果不在计算的过程中模 (10^9+7)(或者别的一些数),答案可能会超过 long long 的表示范围。而如果两个数 (a,b) 满足 (0 le a,b lt 10^9+7),则对其进行加、减、乘、除(整除或取余)操作,都不会让结果超过 long long 的表示范围(当然,除法运算会复杂一点,不能简单地除,除以 (a) 需要转变为乘以 (a) 的逆,这部分不作为这篇随笔的讨论范围),然后计算的结果再对 (10^9+7) 取余,又能保证结果小于 (10^9+7) 了。

同时,对于算术运算,我们能够证明在计算过程中不停地模一个数,和计算完了之后再模这个数的结果是一样的。这部分相信学过 同余 的同学应该也都能够理解。

所以最主要的目的就是:让我们的计算过程用 long long 就可以解决。

那么为什么一般都选择 (10^9+7) 或者 (10007) 这样的数呢?

我们会发现一般取余的数都是 素数 ,这也是有原因的。

假设我要输出的是答案模 (m) 的结果(即答案除以 (m) 的余数)。假设 (m) 是有一个有较多约数的数,同时在数据中存在 (q) 满足 (gcd(m,q) = d gt 1) (即假设有一个数 (q) ,它和 (m) 的最大公约数是一个大于 (1) 的数 (d)),即存在 —— (m = a imes d, q = b imes d),则有以下等式:

[q \% m = q - m imes [q / m] = q - m imes [b / a] ]

(这里 ([x]) 表示 (x) 向下取整的结果)其中 (b/a) 的结果是 ([0,b]) 范围内的正整数,也就是说,([b/a]) 的结果只有 (b+1) 种可能,而 (m) 是一个预先确定的数。因此,上式的值就只有 (b+1) 种可能了。这样,虽然模运算之后的余数仍然在 ([0,m-1]) 范围内,但是它的取值仅限于等式可能取到的那些值,也就是说余数的分布变得不均匀了。所以,(m) 的约数越多,发生这种余数不均匀的情况就越频繁,冲突的几率就越高。而素数的约数是最少的,因此一般选 (m) 为小于某个区域长度的最大素数。于是 (10^9+7) 就变成一个很合适的选择方案,一方面能保证记起来比较方便,另一方面也能保证模 (10^9+7) 的结果不会超出 long long 表示范围。

原文地址:https://www.cnblogs.com/quanjun/p/14440565.html