矩阵快速幂取模

来源:互联网 发布:opengl mac性能差 编辑:程序博客网 时间:2024/05/16 05:17

矩阵快速幂=矩阵乘法+快速幂

矩阵乘法

这里写图片描述
伪代码实现

Mat operator*(Mat a,Mat b) {    Mat c;     for   i:0 --> len           for   j:0-->len              c.mat[i][j] = 0;                  for   k:0-->len                      c.mat[i][j]=(c.mat[i][j] + (a.mat[i][k]*b.mat[k][j])%MOD)%MOD;          return c;}

时间复杂度O(n^3)

实数快速幂

假设你已经有一个函数F(x) = k^x 它可以求 k^1 直到 k^(n-1)
现在的问题是 如何求F(n)?

分治思想

  1. 当n是偶数的时候:F(n)=F(n/2)*F(n/2)
  2. 当n是奇数的时候:转化成偶数的情况 F(n) = k * F(n - 1)

伪代码实现

    /*递归写法*/int fast_mod(int k, int n, int MOD){     n == 0:         return 1;       n是奇数:         return k * fast_mod(k, n -1, MOD) % MOD;    n是偶数:         p = fast_mod(k, n >> 1, MOD);         return p * p % MOD;}
    /*非递归写法*/int quickmod(int a, int b){      ans = 1;     只要b不等于0:        如果b是奇数:              ans = (ans*a)%mod;  b--;        如果b是偶数:        b/=2;          a = ((a%mod)*(a%mod))%mod;               return ans;  } 

时间复杂度O(logN)

矩阵快速幂

伪代码实现

Mat fast_mod(Mat A, int n, int MOD){     n == 0:         return E;       n是奇数:         return MulMat(A, fast_mod(A, n - 1), MOD);    n是偶数:         p = fast_mod(k, n >> 1, MOD);         return MulMat(p, p, MOD);}/*对于任何一个矩阵A,定义A^0 = E。E是单位矩阵*/

朴素矩阵幂运算时间复杂度是O(n^3*m),矩阵快速幂时间复杂度是O(n^3*log m)

例题:Fibonacci

poj-3070

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 Fibonacci sequence is.

这里写图片描述

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

Input

The input test file will contain multiple test 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 the number −1.

Output

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

Sample Input

0
9
999999999
1000000000
-1

Sample Output

0
34
626
6875

原理

F[n]=F[n-1]+F[n-2];
F[0]=0;F[1]=1;F[2]=1;

这里写图片描述

这里写图片描述
故而,此题使用矩阵快速幂取模方法

代码


/*手残党代码*/#include <cstdio>#include <iostream>using namespace std;const int MOD = 10000;int fast_mod(int n)    // 求 (t^n)%MOD{    int t[2][2] = {1, 1, 1, 0};     //起始矩阵    int ans[2][2] = {1, 0, 0, 1};  // 初始化为单位矩阵    int tmp[2][2];    //自始至终都作为矩阵乘法中的中间变量    while(n)    {        if(n&1)  //n 是奇数,先取出1.实现 ans *= t; 其中要先把 ans赋值给 tmp,然后用 ans = tmp * t        {            for(int i=0;i<2;++i)                for(int j = 0;j<2;++j)                    tmp[i][j]=ans[i][j];            ans[0][0]=ans[1][1]=ans[0][1]=ans[1][0] = 0;  //注意这里要都赋值成 0            for(int i=0;i<2;++i)    //ans 乘以一个 起始矩阵            {                for(int j=0; j<2;++j)                {                    for(int k=0;k<2;++k)                        ans[i][j]=(ans[i][j]+(tmp[i][k]*t[k][j])%MOD)%MOD;                }            }        }        //下边要实现 t *= t 的操作,同样要先将t赋值给中间变量 tmp ,t清零,之后 t = tmp* tmp        for(int i = 0; i < 2; ++i)            for(int j = 0; j < 2; ++j)                tmp[i][j] = t[i][j];        t[0][0] = t[1][1] = 0;        t[0][1] = t[1][0] = 0;        for(int i = 0; i < 2; ++i)      //矩阵乘法        {            for(int j = 0; j < 2; ++j)            {                for(int k = 0; k < 2; ++k)                    t[i][j]=(t[i][j]+(tmp[i][k]*tmp[k][j])%MOD)%MOD;            }        }        n/=2;    }    return ans[0][1];}int main(){    int n;    while(scanf("%d",&n) && n != -1)    {        printf("%d\n", fast_mod(n));    }    return 0;}
/*高效代码*/#include <cstdio>#include <iostream>using namespace std;const int MOD = 10000;struct matrix{    int m[2][2];}ans, base;matrix multi(matrix a, matrix b)    //结构体封装{    matrix tmp;    for(int i = 0; i < 2; ++i)    {        for(int j = 0; j < 2; ++j)        {            tmp.m[i][j] = 0;                for(int k = 0; k < 2; ++k)                    tmp.m[i][j]=(tmp.m[i][j]+(a.m[i][k]*b.m[k][j])%MOD)%MOD;        }     }     return tmp;}int fast_mod(int n)  // 求矩阵 base 的  n 次幂{     base.m[0][0] = base.m[0][1] = base.m[1][0] = 1;     base.m[1][1] = 0;     ans.m[0][0] = ans.m[1][1] = 1;  // ans 初始化为单位矩阵     ans.m[0][1] = ans.m[1][0] = 0;     while(n)     {         if(n & 1)  //实现 ans *= t; 其中要先把 ans赋值给 tmp,然后用 ans = tmp * t         {             ans = multi(ans, base);         }         base = multi(base, base);         n >>= 1;     }     return ans.m[0][1]; }int main(){    int n;    while(scanf("%d", &n) && n != -1)    {        printf("%d\n", fast_mod(n));    }    return 0;}
1 0
原创粉丝点击