poj3070矩陣 快速冪

Fibonacci

Time Limit: 1000MS

Memory Limit: 65536K

Total Submissions: 9524

Accepted: 6771

Description

In the Fibonacci integer sequence, F0 =0, F1 = 1, and Fn = Fn −1 + Fn − 2 for n ≥2. For example, the first ten terms of the Fibonacci sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

An alternative formula for the Fibonaccisequence is

.

Given an integer n, your goalis to compute the last 4 digits of Fn.

Input

The input test file will contain multipletest cases. Each test case consists of a single line containing n (where 0 ≤ n ≤1,000,000,000). The end-of-file is denoted by a single line containing thenumber −1.

Output

For each test case, print the last fourdigits of Fn. If the last four digits of Fn areall zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod10000).

Sample Input

0

9

999999999

1000000000

-1

Sample Output

0

34

626

6875

Hint

As a reminder, matrix multiplication isassociative, and the product of two 2 × 2 matrices is given by

.

Also, note that raising any 2 × 2 matrixto the 0th power gives the identity matrix:

.

本題的解法在題中已經講得很清楚了。此題如果採用矩陣乘方的樸素算法,n過大時,會超時,所以在此採用矩陣乘方的快速冪算法。

有關快速冪的講解如下:

矩陣的快速冪是用來高效地計算矩陣的高次方的。將樸素的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中的最右端開始計算到最左端。細節就說到這,下面給核心代碼:

1 while(N)

2  {

3                 if(N&1)

4                        res=res*A;

5                 n>>=1;

6                 A=A*A;

7  }

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

 

本題的源代碼如下:

C:

#include<stdio.h>

void matrix_mul(int a[2][2],int b[2][2],intmul[2][2])

{

         inti,j,k;

         intc[2][2];

         for(i=0;i<2;i++)

         {

                   for(j=0;j<2;j++)

                   {

                            c[i][j]=0;

                            for(k=0;k<2;k++)

                            {

                                     c[i][j]=(c[i][j]+a[i][k]*b[k][j])%10000;

                            }

                   }

         }

         for(i=0;i<2;i++)

         {

                   for(j=0;j<2;j++)

                   {

                            mul[i][j]=c[i][j];

                   }

         }

}

int main()

{

         intn;

         while(scanf("%d",&n)!=EOF&&(n!=-1))

         {

                   inta[2][2]={1,1,1,0};

                   intmul[2][2]={1,0,0,1};

                   while(n)

                   {

                            if(n&1)

                            {

                                     matrix_mul(mul,a,mul); //注意理解參數的傳遞

                            }

                            n>>=1;

                            matrix_mul(a,a,a); //注意理解參數的傳遞

                   }

                   printf("%d\n",mul[0][1]);

         }

         return0;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章