矩阵快速幂取模

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

矩阵乘法

矩阵快速幂取模_第1张图片
伪代码实现

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 
#include 

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 
#include 
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;
}

你可能感兴趣的:(快速幂)