RoNgDaZhOnG

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Codevs1732,这道题要求求fibonacci数列的第N项,1 <= n <= 100000000000000,非常大,普通的O(N)的求法肯定会TLE,所以我们需要用的快速幂矩阵乘法,在O(logN)的时间内即可求出。
矩阵的乘法是这样的:
我们定义X(i,j)表示矩阵第i行第j列的元素。
我们定义两个矩阵A和B,A有n行m列,B有m行p列,则此时矩阵A和B的乘法有定义(当且仅当A的列数=B的行数时,A*B有定义):
A*B=C,矩阵C为n行p列 ,C(i,j)=Σ(A(i,k)*B(k,j)),1<=k<=m。矩阵的乘法可以这样用程序表达:

struct Matrix{
       qint A[10][10];
       int m,n;                //表示该矩阵有m行n列 
       friend Matrix operator * (const Matrix a,const Matrix b){
              Matrix ret;
              ret.m=a.m,ret.n=b.n;
              for(int i=0;i<a.m;i++){
                      for(int j=0;j<b.n;j++){
                              ret.A[i][j]=0;
                              for(int k=0;k<b.m;k++){ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD;}
                      }
              }                        
              return ret;
       }
};

矩阵的乘法有结合律但没有交换律,即(A*B)*C等于A*(B*C),但是A*B不等于B*A。由于矩阵的乘法支持结合律,所以可以利用快速幂的思想在O(logN)的时间内求出矩阵A ^ N。矩阵可以很好的表示线性递推关系。例如:
f(n)=a1*f(n-1) + a2*f(n-2) + ······ + ad*f(n-d),则我们可以设矩阵:
F(N)=|f(n-d+1) |  ( 共d行1列)
         |    ······   |
         |   f(n-1)  |
         |    f(n)    |                                                                    
我们再设矩阵A=
|0,1,0 ······ 0|
|0,0,1 ······ 0|
| ····················· |
|0,0,0 ······ 1|
|a1,a2,····ad|
(共d行d列),
则存在下列关系A*F(N-1)=F(N)。
于是我们就可以通过计算A的幂来快速求F(N)了。

贴一个codevs1732的标程:

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 using namespace std;
 5 typedef long long qint;
 6 const int MOD=1000000007;
 7 struct Matrix{
 8        qint A[10][10];
 9        int m,n;//m行n列的矩阵 
10        friend Matrix operator * (const Matrix a,const Matrix b){
11               Matrix ret;
12               ret.m=a.m,ret.n=b.n;
13               for(int i=0;i<a.m;i++){
14                       for(int j=0;j<b.n;j++){
15                               ret.A[i][j]=0;
16                               for(int k=0;k<b.m;k++){
17                                       ret.A[i][j]=(ret.A[i][j]+a.A[i][k]*b.A[k][j])%MOD;
18                               }
19                       }
20               }                        
21               return ret;
22        }
23 };
24 
25 int get_ans(qint n){
26     if(n<=1) return n;
27     n=n-1;
28     bool f=true;
29     Matrix st,now,pow;
30     
31     st.A[0][0]=0,st.A[1][0]=1;
32     st.m=2,st.n=1;
33 
34     pow.A[0][0]=0,pow.A[0][1]=1;
35     pow.A[1][0]=1,pow.A[1][1]=1;
36     pow.m=2,pow.n=2;
37     
38     while(n>0){
39                if(n & 1){
40                     if(f){now=pow;f=false;}
41                     else{now=now*pow;}
42                }
43                pow=pow*pow;
44                n=n>>1;
45     }
46 
47     now=now*st;
48     return now.A[1][0];
49 }
50                     
51                                    
52                           
53 int main(){
54     qint n;
55     while(scanf("%lld",&n)!=EOF){
56             printf("%d\n",get_ans(n));
57     }
58     
59     return 0;
60 }

1msAC,各种爽。

posted on 2017-03-12 09:33  学无止境-1980  阅读(111)  评论(0编辑  收藏  举报