很多地方用到模運算,這裡說明模運算的一些規律,並加以證明。 後續會對這些理論實際的應用加以記錄和說明。
1. 模運算是取餘運算(記做 % 或者 mod),具有周期性的特點。 m%n的意思是n除m後的餘數, 當m遞增時m%n呈現周期性特點, 並且n越大,周期越長,周期等於n。
例如
0 % 20 = 0,1 % 20 = 1, 2 % 20 = 2, 3 % 20 = 3, ..., 19 % 20 = 19
20 % 20 = 0,21 % 20 = 1,22 % 20 = 2,23 % 20 = 3, ...,39 % 20 = 19
2. 如果 m % n = r,那麼可以推出如下等式
m = k * n + r (k為大於等於0的整數, r <= m)
3. 同餘式, 表示正整數a,b對n模數,它們的餘數相同,記做 a ≡ b mod n或者a = b (mod n)。
根據2的等式可以推出 a = kn + b 或者 a - b = kn
證明: ∵ a = k1 * n + r1
b = k2 * n + r2
∴ a - b = (k1 - k2) * n + (r1 - r2)
a = k * n + (r1 - r2) + b
∵ a, b對n模數同餘,r1 = r2
∴ a = k * n + b (k = k1 - k2)
4. 模運算規則, 模運算與基本四則運算有些相似,但是除法例外。其規則如下
(a + b) % n = (a % n + b % n) % n (1)
(a - b) % n = (a % n - b % n) % n (2)
(a * b) % n = (a % n * b % n) % n (3)
ab % n = ((a % n)b) % n (4)
相關證明:http://hi.baidu.com/ckh%5F0330/blog/item/bb2c4d8873df60ba0e24441e.html
模取冪運算a^b mod c :
直接插入主題:
1.當a,b,c 都比較小的時候,可以使用赤裸裸的暴力
虛擬碼:
v:=1;
for i := 1 to b begin
v:=v*a;
v:=v mod c;
end
這也是我們在第一次遇到這種問題的時候首先能想到的.
2.a,b,c都比較大的時候
這裡需要考慮c的大小了,假設c*c<2^64吧(再大就只能再做特殊處理了)
b比較大的話使用1的方法顯然時間上是承受不了的,所以可以利用所謂的二分法.
b=b0+b1*2^1+b2*2^2+...+bn*2^n
顯然a^b可以變成若干項的乘積
虛擬碼:
v:=1;
while b<>0 do begin
if (b and 1= 1) do begin v:=v*a;v:=v mod c;end
a:=a*a;
a:=a mod c;
b:=b shr 1;
end
3.如果c很大,那麼需要使用到類比乘法來避免溢出,當然如果c已經大到10^100,那麼只能用高精了..這裡只能處理最多c=2^64-1的情況吧
虛擬碼:
int mul(int a,int b,int c)
{
int ret=0,tmp=a%c;
while(b)
{
if(b&0x1)if((ret+=tmp)>=c)ret-=c;
if((tmp<<=1)>=c)tmp-=c;
b>>=1;
}
return ret;
}
4.如果b已經爆大,那麼使用logb的演算法顯然已經力不從心
於是可以考慮利用迴圈節的方法來求解
如果c比較小,那麼可以直接暴力得到迴圈節
對於a^b mod c
a.if gcd(a,c)==1
那麼可以知道它的迴圈節開始位置必然是1,而且迴圈節長既為它的歐拉函數的因子
因為有a^p mod c= 1
所以p可以看成是周期
b.if gcd(a,c)!=1 那麼迴圈節是否一定不從1開始呢?答案是否定的
why?
因為假設存在某個L'使
a mod c = a^(1+L') mod c= a* a^L' mod c
那麼可以解到許多滿足條件的B',使a*B' = a mod c (mod c)
解的個數就是gcd(a,c),然後如果能找到a^L' = B' (mod c)
那麼其開始位置依然可以是1
當然其他大多數情況下迴圈節開始位置都不是1
好了下面用暴力得到了迴圈節開始位置spos,和迴圈節長len
下面用到公式
就可以在比較快的時間內求解了
如果c非常大那怎麼辦?
可以利用抽屜原理+baby-step,giant-step擴充應該可以得到迴圈節的長度,接下來迴圈節的開始位置我還沒有想到比較好的演算法,暫時只能暴力了-_-,誰有思路請留言謝謝~
ps:acm競賽經常要用到模運算和模取冪運算,高優的演算法同時也要兼顧處理的範圍。
資料來自:http://hi.baidu.com/aekdycoin
http://hi.baidu.com/ckh%5F0330
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/akof1314/archive/2009/07/29/4391119.aspx