快速幂取模算法模板
求a^b%c(這就是著名的RSA公鑰的加密方法),當a,b很大時,直接求解這個問題不太可能?
算法1:利用公式a*b%c=((a%c)*b)%c,這樣每一步都進行這種處理,這就解決了a^b可能太大存不下的問題,但這個算法的時間復雜度依然沒有得到優化
代碼如下:
int modexp_simple(int a,int b,int n)
{
int ret = 1;
while (b--)
{
ret = a * ret % n;
}
return ret;
}
可以把b按二進制展開為:b = p(n)*2^n? + ?p(n-1)*2^(n-1)? +…+ ? p(1)*2 ?+? p(0)
其中p(i) (0<=i<=n)為 0 或 1
這樣 a^b =? a^?(p(n)*2^n? +? p(n-1)*2^(n-1)? +...+? p(1)*2? +? p(0))
?????????????? =? a^(p(n)*2^n)? *? a^(p(n-1)*2^(n-1))? *...*? a^(p(1)*2)? *? a^p(0)
對于p(i)=0的情況, a^(p(i) * 2^(i-1)?) =? a^0? =? 1,不用處理
我們要考慮的僅僅是p(i)=1的情況
化簡:a^(2^i)? =?a^(2^(i-1)? * 2) = (? a^(? p(i)? *? 2^(i-1)? )? )^2
(這里很重要!!具體請參閱秦九韶算法:http://baike.baidu.com/view/1431260.htm)利用這一點,我們可以遞推地算出所有的a^(2^i)
當然由算法1的結論,我們加上取模運算:
a^(2^i)%c = ( (a^(2^(i-1))%c) * a^(2^(i-1)))? %c
于是再把所有滿足p(i)=1的a^(2^i)%c按照算法1乘起來再%c就是結果,?即二進制掃描從最高位一直掃描到最低位
實例代碼:遞歸
//計算a^bmodn
int modexp_recursion(int a,int b,int n)
{
int t = 1;
if (b == 0)
return 1;
if (b == 1)
return a%n;
t = modexp_recursion(a, b>>1, n);
t = t*t % n;
if (b&0x1)
{
t = t*a % n;
}
return t;
}
實例代碼2:非遞歸優化?
#include <iostream>
using namespace std;
//計算a^bmodn
int modexp(int a,int b,int n)
{
int ret=1;
int tmp=a;
while(b)
{
//基數存在
if(b&0x1) ret=ret*tmp%n;
tmp=tmp*tmp%n;
b>>=1;
}
return ret;
}
int main()
{
cout<<modexp(2,10,3)<<endl;
return 0;
}
另外的一種寫法3:
long?long bigmod(long?long a,long?long b,long?long m)
{
????long?long d,t;
??? d=1;
??? t=a;
????while?(b>0)
????{
????????if?(b%2==1)
??????????? d=(d*t)%m;
??????? b/=2;
??????? t=(t*t)%m;
????}
????return?d;
}
參考文章來源:Reait? Home(http://www.reait.com/blog.html)?
總結
- 上一篇: dnf今年五一会推出五一套麽?
- 下一篇: hdu 1317——XYZZY