資訊學競賽中計算結果對 $10^9+7$ 取餘數的原因

quanjun發表於2021-02-24

大家在學習資訊學競賽的過程中,總是會遇到要求計算結果對 \(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 \times d, q = b \times d\),則有以下等式:

\[q \% m = q - m \times [q / m] = q - m \times [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 表示範圍。

相關文章