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

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

本題大意:求a1的b1次方加a2的b2次方一直加到an的bn次方,用他們冪的和對一個數x取餘,把結果輸出!

矩陣的快速冪是用來高效地計算矩陣的高次方的。將樸素的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次,少於原來的5次。

其實大家還可以取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中的最右端開始計算到最左端。細節就說到這,下面給核心程式碼:

while(N)
 {
               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 .

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

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

1.多重揹包問題

2.樹狀陣列

3.狀態壓縮DP

……………還有很多。。。究其根本還是那句話:化連續為離散。。很多時候我們並不是為了解決一個問題而使用二進位制,更多是時候是為了優化而使用它。所以如果你想讓你的程式更加能適應大資料的情況,那麼學習學習二進位制及其演算法思想將會對你有很大幫助。


解決本題需知的兩個知識點:

1、(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 ;

Problem Description People are different. Some secretly read magazines full of interesting girls' pictures, others create an A-bomb in their cellar, others like using Windows, and some like difficult mathematical games. Latest marketing research shows, that this market segment was so far underestimated and that there is lack of such games. This kind of game was thus included into the KOKODáKH. The rules follow: 

Each player chooses two numbers Ai and Bi and writes them on a slip of paper. Others cannot see the numbers. In a given moment all players show their numbers to the others. The goal is to determine the sum of all expressions AiBi from all players including oneself and determine the remainder after division by a given number M. The winner is the one who first determines the correct result. According to the players' experience it is possible to increase the difficulty by choosing higher numbers. 

You should write a program that calculates the result and is able to find out who won the game. 


Input The input consists of Z assignments. The number of them is given by the single positive integer Z appearing on the first line of input. Then the assignements follow. Each assignement begins with line containing an integer M (1 <= M <= 45000). The sum will be divided by this number. Next line contains number of players H (1 <= H <= 45000). Next exactly H lines follow. On each line, there are exactly two numbers Ai and Bi separated by space. Both numbers cannot be equal zero at the same time.
Output For each assingnement there is the only one line of output. On this line, there is a number, the result of expression 

(A1B1+A2B2+ ... +AHBH)mod M.


Sample Input 3 16 4 2 3 3 4 4 5 5 6 36123 1 2374859 3029382 17 1 3 18132
Sample Output 2 13195 13

ac程式碼

<pre name="code" class="cpp">#include<stdio.h>
int fun1(__int64 a,__int64 b,__int64 mod)
{
	__int64 ans=1;
	while(b)
	{
		if(b&1)
		{
			ans=ans*a%mod;
		}
		a=a*a%mod;
		b/=2;
	}
	return ans;
}
int main()
{
	__int64 n,m,a,b,s,i,mod;
	scanf("%I64d",&n);
	while(n--)
	{
		scanf("%I64d%I64d",&mod,&m);
		__int64 s=0;
		for(i=0;i<m;i++)
		{
			scanf("%I64d%I64d",&a,&b);  
			s=s+fun1(a,b,mod);   //把每一個冪指數取餘後加起來 
		}
		s=s%mod;   //利用同餘定理,把求的和再取餘 
		printf("%I64d\n",s);
	}
	return 0;
}

運算規則

模運算與基本四則運算有些相似,但是除法例外。其規則如下:

(a + b) % p = (a % p + b % p) % p (1)

(a – b) % p = (a % p – b % p) % p (2)

(a * b) % p = (a % p * b % p) % p (3)

(a^b) % p = ((a % p)^b) % p (4)

結合律:

((a+b) % p + c) % p = (a + (b+c) % p) % p (5)

((a*b) % p * c)% p = (a * (b*c) % p) % p (6)

交換律:

(a + b) % p = (b+a) % p (7)

(a * b) % p = (b * a) % p (8)

分配律:

((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p (9)

重要定理

若a≡b (% p),則對於任意的c,都有(a + c) ≡ (b + c) (%p);(10)

若a≡b (% p),則對於任意的c,都有(a * c) ≡ (b * c) (%p);(11)

若a≡b (% p),c≡d (% p),則 (a + c) ≡ (b + d) (%p),(a – c) ≡ (b – d) (%p),

(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p); (12)