霍爾筆記

由 LeetCode 1922 數學題,推導乘法同餘性質

約 1,194 字 --

最近在看到了 LeetCode 1922. Count Good Numbers 的題目後,發現幾乎是一題純數學的題目,需要理解 Modular Exponentiation(模冪運算)這個技巧才能夠順利解題。

想當初在學習非對稱式加密的核心技術 RSA 時,所接觸到的 Euler’s Theorem(歐拉定理)就大量用到模(Mod,取餘數)運算。

這次的題目正巧也需要對於模運算性質有所理解,才能得出有效率的解法。在理解完題意之後,結論是需要透過程式來計算以下算式:

(5x4y)mod(109+7)(5^x \cdot 4^y) \bmod (10^9 + 7)

其中題目限制 x,y1015x, y \leq 10^{15},這也就意味 5x4y5^x \cdot 4^y 的數值可能相當大,遠大於絕大部分的程式語言中單一變數能儲存的數字上限。

那要如何計算出結果呢?既然最終要取模 mod(109+7)\bmod (10^9 + 7),這個模數(109+710^9 + 7)也在變數的可儲存範圍內,那我們只要確保每次的中間計算結果都不會超出變數上限即可,因此解法的關鍵就在於「拆」。

怎麼拆呢?可以像是 430=4154154^{30} = 4^{15} \cdot 4^{15} 將較大的數字拆成兩個較小的數字相乘,然後分別取模。

(xaxb)modm=((xamodm)(xbmodm))modm(★)(x^a \cdot x^b) \bmod m = ((x^a \bmod m) \cdot (x^b \bmod m)) \bmod m\tag*{(★)}

上述公式便是將大數拆小再分別取模的等式,但在寫出此等式的當下我其實不太確定是否能成立,不過只要能證明它,我們就有理論支持,能透過一般程式語言來得出計算結果。

乘法同餘、餘數定理

上述要證明的式子,可以將其簡化成:

(ab)modm=((amodm)(bmodm))modm(1)(a \cdot b) \bmod m = ((a \bmod m) \cdot (b \bmod m)) \bmod m \tag*{(1)}

式子 (1) 稱作乘法同餘性質(Multiplicative Congruence),舉例來說,(146)mod5=4(14 \cdot 6) \mod 5 = 4,也等同於分別取模相乘後,再將結果取模:

((14mod5)(6mod5))mod5=(41)mod5=4((14 \bmod 5) \cdot (6 \bmod 5)) \bmod 5\\ = (4 \cdot 1) \bmod 5 = 4

但這是否就能說我們想證明的等式成立了呢?也不然,這僅僅是舉一個例子而已。

要適當嚴謹的得出結論,我們需要先了解**餘數定理(Division Theorem)**這個概念:

任意整數 xx 與正整數 mm 必定存在唯一整數對 (q,r)(q, r) 使得

x=qm+r, 0r<mx = q \cdot m + r,\ 0 \leq r < m

舉例來說,14=25+414 = 2 \cdot 5 + 4,其中被除數 x=14x = 14,商數 q=2q = 2、除數 m=5m = 5,餘數 r=4r = 4,而餘數 rr 便是 xxmm 取模的結果,記為 r=xmodmr = x \bmod m

證明乘法同餘

接著,我們可以根據餘數定理,來定義 (ab)modm(a \cdot b) \bmod m 中的 a=q1m+r1, b=q2m+r2a = q_1 \cdot m + r_1,\ b = q_2 \cdot m + r_2,並把 a,ba, b 在式子 (1) 的左式 (ab)modm(a \cdot b) \bmod m 展開:

(ab)modm=((q1m+r1)(q2m+r2))modm(a \cdot b) \bmod m = ((q_1 m + r_1) \cdot (q_2 m + r_2)) \bmod m =(q1q2m2+q1r2m+q2r1m+r1r2)modm= (q_1 q_2 m^2 + q_1 r_2 m + q_2 r_1 m + r_1 r_2) \bmod m =((q1q2m+q1r2+q2r1)m+r1r2)modm= ((q_1 q_2 m + q_1 r_2 + q_2 r_1)m + r_1 r_2) \bmod m

由於 q1,q2,r1,r2,mq_1, q_2, r_1, r_2, m 都是整數,因此他們的乘積及加總的組合也會是整數,將其簡化成 K=q1q2m+q1r2+q2r1K = q_1 q_2 m + q_1 r_2 + q_2 r_1KK 會是一個整數,所以將 a,ba, b 帶入式子 (1) 的左式結果能再簡化成下面式子 (2)

(ab)modm=(Km+r1r2)modm(2)(a \cdot b) \bmod m = (Km + r_1 r_2) \bmod m \tag*{(2)}

根據剛剛從餘數定理出發來定義的 a,ba, b,我們能得出式子 (1) 右式的 amodma \bmod mbmodmb \bmod m 就等同 r1r_1r2r_2 這兩個餘數,因此式子 (1) 右式就能推導出下述式子 (3)。

((amodm)(bmodm))modm=(r1r2)modm(3)((a \bmod m) \cdot (b \bmod m)) \bmod m = (r_1 r_2) \bmod m \tag*{(3)}

只要能證明 (2) 和 (3) 兩個式子的右式等價,整個乘法同餘的證明就大功告成,我們繼續拆解下去:

(Km+r1r2)modm=(r1r2)modm(4)(Km + r_1 r_2) \bmod m = (r_1 r_2) \bmod m \tag*{(4)}

再另外定義一個整數 c=kmc = k \cdot mcc 為除數 mm 的倍數,kk 是個整數),然後令 x=r1r2x = r_1 r_2,想證明的式子 (4) 就等價於下面式子 (5)

(x+c)modm=xmodm(5)(x + c) \bmod m = x \bmod m \tag*{(5)}

根據餘數定理令 x=qm+rx = q \cdot m + rc=kmc = k \cdot m 展開帶入式子 (5) 的左式:

(x+c)modm(5 Left)(x + c) \bmod m \tag*{(5 Left)} =(qm+r+c)modm= (q \cdot m + r + c) \bmod m =(qm+r+km)modm= (q \cdot m + r + k \cdot m) \bmod m =((q+k)m+r)modm= ((q + k) \cdot m + r) \bmod m

其中 (q+k)m+r(q + k) \cdot m + r 剛好就符合餘數定理的架構,當此式對 mm 取餘,答案就為 rr,所以得出

(x+c)modm(5 Left)(x + c) \bmod m \tag*{(5 Left)} =r= r =xmodm(5 Right)= x \bmod m \tag*{(5 Right)}

如此便得證,將 (5) 式的左式和右式之間的等號連接起來。

參考資料

  1. Wiki - 歐拉定理
  2. Wiki - 模算數
  3. LeetCode 1922. Count Good Numbers
  4. Wiki - 分配律
  5. Centennial College - Modular Numbers and Cryptography
  6. Wiki - 餘數定理
演算法學習筆記