1. 程式人生 > >快速冪二進位制取模演算法

快速冪二進位制取模演算法

       矩陣的快速冪是用來高效地計算矩陣的高次方的。將樸素的o(n)的時間複雜度,降到log(n)。這裡先對原理(主要運用了矩陣乘法的結合律)做下簡單形象的介紹:一般一個矩陣的n次方,我們會通過連乘n-1次來得到它的n次冪。

       但做下簡單的改進就能減少連乘的次數,方法如下:

     把n個矩陣進行兩兩分組,比如:A*A*A*A*A*A  =>  (A*A)*(A*A)*(A*A),這樣就只需要計算一次A*A,然後將結果(A*A)連乘自己兩次就能得到A^6,即(A*A)^3=A^6。算一下發現這次一共乘了3次,少於原來的3次。其實大家還可以取A^3作為一個基本單位。原理都一樣:利用矩陣乘法的結合律,來減少重複計算的次數。

     以上都是取一個具體的數來作為最小單位的長度,這樣做雖然能夠改進效率,但缺陷也是很明顯的,取個極限的例子(可能有點不恰當,但基本能說明問題),當n無窮大的時候,你現在所取的長度其實和1沒什麼區別。所以就需要我們找到一種與n增長速度”相適應“的”單位長度“,那這個長度到底怎麼去取呢???這點是我們要思考的問題。

    有了以上的知識,我們現在再來看看,到底怎麼迅速地求得矩陣的N次冪。

      既然要減少重複計算,那麼就要充分利用現有的計算結果咯!~怎麼充分利用計算結果呢???這裡考慮二分的思想。大家首先要認識到這一點:任何一個整數N,都能用二進位制來表示。。這點大家都應該知道,但其中的內涵真的很深很深(這點筆者感觸很深,在文章的最後,我將談談我對的感想)!!

      計算機處理的是離散的資訊,都是以0,1來作為訊號的處理的。可想而知二進位制在計算機上起著舉足輕重的地位。它能將模擬訊號轉化成數字訊號,將原來連續的實際模型,用一個離散的演算法模型來解決。  好了,扯得有點多了,不過相信這寫對下面的講解還是有用的。

     回頭看看矩陣的快速冪問題,我們是不是也能把它離散化呢?比如A^19  =>  (A^16)*(A^2)*(A^1),顯然採取這樣的方式計算時因子數將是log(n)級別的(原來的因子數是n),不僅這樣,因子間也是存在某種聯絡的,比如A^4能通過(A^2)*(A^2)得到,A^8又能通過(A^4)*(A^4)得到,這點也充分利用了現有的結果作為有利條件。下面舉個例子進行說明:

    現在要求A^156,而156(10)=10011100(2) ,也就有A^156=>(A^4)*(A^8)*(A^16)*(A^128)  考慮到因子間的聯絡,我們從二進位制10011100中的最右端開始計算到最左端。細節就說到這,下面給核心程式碼:

if(N&1)  
       res=res*A;     //二進位制位為1時執行此步  
 n>>=1;  
 A=A*A;     //實質上這步只是不斷地使二進位制位從右向左移動,實現的是使res乘的A值等於2^(對應位+1)  

裡面的乘號,是矩陣乘的運算,res是結果矩陣。

第3行程式碼每進行一次,二進位制數就少了最後面的一個1。二進位制數有多少個1就第3行程式碼就執行多少次。

即每次執行第3行程式碼結果為res* a^4 * a^8  *  a^16  *a^128 .

現在我就說下我對二進位制的感想吧:

我們在做很多”連續“的問題的時候都會用到二進位制將他們離散簡化

Description

Fermat's theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)

Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.

Input

Input contains several test cases followed by a line containing "0 0". Each test case consists of a line containing p and a.

Output

For each test case, output "yes" if p is a base-a pseudoprime; otherwise output "no".

Sample Input

3 2
10 3
341 2
341 3
1105 2
1105 3
0 0

Sample Output

no
no
yes
no
yes
yes
#include<cstdio>
#define N 45000
struct st
{
	int a,b;
}s[N];
long quickpow(long n,long m,long mod)
{
	long ans=1,base=n;
	
	while(m)
	{
		if(m&1)
		  ans=((ans%mod)*(base%mod))%mod;
		base=((base%mod)*(base%mod))%mod;
		m>>=1;				
	}
	return ans;
}
int main()
{
	int t,n,i,h;
	long sum,m;
	scanf("%d",&t);
	while(t--)
	{
		sum=0;
		scanf("%ld",&m);
		scanf("%d",&h);
		for(i=0;i<h;i++)
		   scanf("%d%d",&s[i].a,&s[i].b);
		for(i=0;i<h;i++)
		   sum+=quickpow(s[i].a,s[i].b,m);
		sum%=m;
		printf("%ld\n",sum);
	}
	return 0;
}

(a+b+c+d+e)%x=(a%x+b%x+c%x+d%x+e%x)%x ;

2、(a*b*c*d*e)%x=(a%x*b%x*c%x*d%x*e%x)%x ;