快速冪取餘,冪取餘

來源:互聯網
上載者:User

快速冪取餘,冪取餘

求a^b mod c

 演算法1.

首先直接地來設計這個演算法:

int  ans=1, i;for(i=1;i<=b;i++)    ans*=a;ans%=c;

這個演算法的時間複雜度體現在for迴圈中,為O(b).

這個演算法存在著明顯的問題,如果a和b過大,很容易就會溢出。

那麼,我們先來看看第一個改進方案:在講這個方案之前,要先有這樣一個公式:

a^b mod c=(a mod c)^b

引理:

(a *b) mod c =[ ( a mod c )* (b mod c) ] mod c ;

證明: 設 a mod c =d,b mod c= e;

       則:a=t*c + d ;  b=k*c + e ;

       (a*b)mod c = (t*c+d)(t*c+e)

                 = (tk c^2 + ( te+dk ) *c + d*e) mod c

                 =de mod c

即積的取餘等於取餘的積的取餘.

(a ^ b)mod c 由上述公式迭代即可得到 ( a mod c)^b.

證明了以上的公式以後,我們可以先讓a關於c取餘,這樣可以大大減少a的大小,於是不用思考的進行了改進:

 演算法2:

int ans = 1 , i ;   a = a % c; //加上這一句  for ( i = 1;i<=b;i++)      ans = ans * a;   ans = ans % c;  

既然某個因子取餘之後相乘再取餘保持餘數不變,那麼新算得的ans也可以進行取餘,所以得到比較良好的改進版本。 

演算法3:

int  ans = 1 ,i ;  a = a % c;for(int i = 1;i<=b;i++)     ans = (ans * a) % c; //這裡再取了一次餘 ans = ans % c; 

 

這個演算法在時間複雜度上沒有改進,仍為O(b),不過已經好很多的,但是在c過大的條件下,還是很有可能逾時,所以,我們推出以下的快速冪演算法。 

快速冪取餘依賴於以下公式:


 

那麼我們可以得到以下演算法: 

演算法4: 

int  ans = 1 ,i ; a = a % c; if (b%2==1)  ans = (ans * a) mod c; //如果是奇數,要多求一步,                     可以提前算到 ans 中。k = (a*a) % c;  //我們取a^2 而不是a for( i = 1;i<=b/2;i++)     ans = (ans * k) % c;  ans = ans % c;   


我們可以看到,我們把時間複雜度變成了O(b/2).

當然,這樣子治標不治本。

但我們可以看到,當我們令k = (a * a) mod c時,狀態已經發生了變化,我們所要求的最終結果即為 k^(b/2) mod c

而不是原來的a^b mod c,所以我們發現這個過程是可以迭代下去的。當然,對於奇數的情形會多出一項a mod c,所以為了完成迭代,當b是奇數時,我們通過 ans = (ans * a) % c;

來彌補多出來的這一項,此時剩餘的部分就可以進行迭代了。 

形如上式的迭代下去後,當b=0時,所有的因子都已經相乘,演算法結束。

於是便可以在O(log b)的時間內完成了。

於是,有了最終的演算法:快速冪演算法。 

演算法5:快速冪演算法  

int ans = 1;a = a % c; while(b>0) {       if(b % 2 == 1)          ans = (ans * a) % c;     b = b/2;     a = (a * a) % c;  }  


將上述的代碼結構化,也就是寫成函數: 

long long  PowerMod (int a, int b, int c) {      int  ans = 1;     a = a % c;     while(b>0) {          if(b % 2 = = 1)             ans = (ans * a) % c;         b = b/2;       //   b>>=1;        a = (a * a) % c;     }     return ans; }  


本演算法的時間複雜度為O(logb),能在幾乎所有的程式設計(競賽)過程中通過,是目前最常用的演算法之一。 

 

以下內容僅供參考: 

 擴充:有關於快速冪的演算法的推導,還可以從另一個角度來想。 

a^b%c 求解這個問題,我們也可以從二進位轉換來考慮: 

將10進位的b轉化成2

進位的運算式:

 

注意此處的an要麼為0,要麼為1,如果為0,那麼這一項就是1,這個對應了上面演算法過程中b是偶數的情況;

為1對應了b是奇數的情況.


pascal 快速冪:取餘

{輸入b,p,k的值,求b^p mod k的值。其中b,p,k*k為長整型數。
範例輸入:2 10 1000,輸出:24}
var b,p,k,t,ans:longint;
begin
readln(b,p,k);
ans:=1; t:=b;
while p>0 do
begin
if odd(p) then ans:=ans*t mod k;
p:=p div 2;
t:=t*t mod k;
end;
writeln(ans);
end.
 
下面是一個矩陣快速冪解斐波那契數列第n項對第m項取餘的程式,但是總是運行出錯,解

按照正常的邏輯是只要求a[2][2]={1,1,1,0}這個矩陣的n次方就可以得到斐波那契數列的第n項(即a[0][1])的值。但是你忽略了一點,就是你在求a[0][1],a[1][0],a[1][1]的值的時候你的a[0][0]的值其實已經改變了,導致你求得的a[0][1]的值不正確,繼而影響到a[1][0]和a[1][1]的值。
因此,我們在遍曆這四個值的時候是不能改變其中任何一個的,只有改完之後才能去改變它的值。所以我們可以用幾個變數先將求得的新矩陣各值存起來,如下:
#include<stdio.h>
int a[2][2]={1,1,1,0},b[2][2]={1,1,1,0};//使用兩個二維數組表示快速冪演算法要用到的矩陣
int main()
{
int n,m,i,j,t,u;
int a1,a2,a3,a4;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(m==-1 && n==-1)//當輸入的m.n值為-1時結束整個演算法
return 0;
/*以下是對於第n項斐波那契數的計算*/
if(n==0)
a[0][0]=0;
else if(n==1 || n==2)
a[0][0]=1;
else
{
for(i=3;i<=n;i++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
t=a[0][0];
a[0][0]=1;//重設矩陣
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
if(m==0)
a[0][0]=0;
else if(m==1 || m==2)
a[0][0]=1;
else
{
for(j=3;j<=m;j++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
u=a[0][0];
a[0][0]=1;//重設矩陣
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
t=t%u;
printf("%d\n",t);
}
return 0;
}

還有一點,就是你的矩陣相乘後兩項寫錯了,自己對比一下改過來吧。

這樣就能得到你想要的結果了。
...餘下全文>>
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.