zoukankan      html  css  js  c++  java
  • 矩阵快速幂

    讲算法肯定要有相应的OJ,这里附上一道题,HDU5950

    大佬博客:链接:https://www.jianshu.com/p/25eba927d9da

    简单讲解下题意。F(n) = F(n-1) + 2F(n-2) + n4,且F(1) = a , F(2) = b,求F(n)%2147493647,其中a、b、n是待输入的参数

    我们把解决这类题目的过程分解为如下步骤:
    1. 把非线性递推式转化为线性递推式(线性递推式可忽略第一步)
    2. 根据线性递推式得到F(n)和F(n+1)的矩阵序列
    3. 根据F(n)和F(n+1)的矩阵序列得到中间的转移矩阵
    4. 根据转移矩阵编写代码

    分步拆解问题

    首先把非线性递推式转换为线性递推式
    ∵ (n+1)4 = n4 + 4n3 + 6n2 + 4n + n0
    ∵ F(n+1) = F(n) + 2F(n-1) + (n+1)4
    ∴ F(n+1) = F(n) + 2F(n-1) + n4 + 4n3 + 6n2 + 4n + n0

    然后我们看下下面的状态转移矩阵

    图(1)

    图(1)左边的矩阵表示F(n)项的矩阵,右边的矩阵表示F(n+1)项的矩阵。而中间的A矩阵就是需要求的转移矩阵。图(1)左边的矩阵怎么得到?我们看刚才得到的递归式

    F(n+1) = F(n) + 2F(n-1) + n4 + 4n3 + 6n2 + 4n + n0

    我们把F(n)放在矩阵顶部,表示第n项的值,然后剩下的元素F(n-1)、 n4、n3、n2、n、 n0 ,去掉系数后与F(n)一起构成一个矩阵。同理,F(n+1)的矩阵也是F(n+1)在顶部,表示第n+1项的值,然后剩下的元素F(n)、 (n+1)4、(n+1)3、(n+1)2、(n+1)、 (n+1)0 去掉系数后与F(n+1)构成一个矩阵。

    好,我们现在得到了F(n)F(n+1)的矩阵,那怎么求转移过去的矩阵A呢?首先,A是一个7×7的矩阵,且根据矩阵相乘规则,可以得到矩阵A,如下图(如果对矩阵相乘不熟悉的可以先看一下矩阵相乘哈)

    图(2)

    好了,到现在为止,得到了图(2)的转移矩阵后,我们解决了前三步,还剩最后一步。怎么把这个转移矩阵应用到代码里面呢?

    题中给出了F(1) = a,F(2) = b
    所以F(3) = 2a + b + 34 = 2a + b + 24 + 4×23 + 6×22 + 4×21 + 20

    图(3)

    为了表述方便。图(3)乘号左边的我们称为转移矩阵A,乘号右边的四个矩阵分别为B2B3B4B5……

    且我们可以得到的信息有
    B2 × A = B3、B3 × A = B4、B4 × A = B5 ……
    B2 × A2 = B4、B2 × A3 = B5、B2 × A4 = B6 ……
    然后我们惊奇的发现:B2 × An-2 = Bn(fn)

    B2的数据都是已知的,所以现在我们需要得到的只是An-2的数据,在 上一篇文章中,我们需要得到的是An的矩阵,代码问题就解决了吧。

    再炒一下上一篇文章的冷饭,本来是根据B2->B3->B4->B5->……->Bn逐步递推得到Bn。现在我们转化为矩阵后,需要求的是A^(n-2)的数据,比如要求A^16,那我就可以直接通过快速幂A^1->A^2->A^4->A^8->A^16来得到了,复杂度由O(n)转化成了O(logn)

    完整代码

    
    
    #include <iostream>
    #include<bits/stdc++.h>
     using namespace std;
    const long long int N = 2147493647; //注意要用 long long int
    void Matrix(long long int (&a)[7][7],long long int b[7][7])  //还是一样的函数
    {
        long long int tmp[7][7] = {0};
        for(int i = 0; i < 7; ++i)
            for(int j = 0; j < 7; ++j)
                for(int k = 0; k < 7; ++k)
                    tmp[i][j] = (tmp[i][j] + a[i][k] * b[k][j]) % N;
        for(int i = 0; i < 7; ++i)
            for(int j = 0; j < 7; ++j)
                a[i][j] = tmp[i][j];
    }
    int main(int argc, const char * argv[])
    {
        long long int sum,T,a,b,n;
        cin>>T;
        while(T--)
        {
            cin>>n>>a>>b;
            if(n==1)
            {
                cout<<a<<endl;    //为了方便读者理解,直接这么定义矩阵了
                continue;
            }
    
    
            long long int temp[7][7] = {1, 2, 1, 4, 6, 4, 1,
                                        1, 0, 0, 0, 0, 0, 0,
                                        0, 0, 1, 4, 6, 4, 1,
                                        0, 0, 0, 1, 3, 3, 1,
                                        0, 0, 0, 0, 1, 2, 1,
                                        0, 0, 0, 0, 0, 1, 1,
                                        0, 0, 0, 0, 0, 0, 1
                                       }; //temp表示的是A^n,cot表示的是最后的结果
            long long int cot[7][7] = {1, 0, 0, 0, 0, 0, 0,
                                       0, 1, 0, 0, 0, 0, 0,
                                       0, 0, 1, 0, 0, 0, 0,
                                       0, 0, 0, 1, 0, 0, 0,
                                       0, 0, 0, 0, 1, 0, 0,
                                       0, 0, 0, 0, 0, 1, 0,
                                       0, 0, 0, 0, 0, 0, 1
                                      };
            n -= 2;
            while(n)  //还是这5行核心代码
            {
                if(n & 1) Matrix(cot,temp);
                Matrix(temp,temp);
                n /= 2;
            }
            sum = 0; //在得到A^(n-2)之后,还需要将B2*A^(n-2)得到Bn,而sum表示的是Bn的最顶部的元素值
            sum = (sum + b*cot[0][0])%N;
            sum = (sum + a*cot[0][1])%N;
            sum = (sum + 16*cot[0][2])%N;
            sum = (sum + 8*cot[0][3])%N;
            sum = (sum + 4*cot[0][4])%N;
            sum = (sum + 2*cot[0][5])%N;
            sum = (sum + cot[0][6])%N;
            cout<<sum<<endl;
        }
        return 0;
    }
    
    
    
     


  • 相关阅读:
    BFS visit tree
    Kth Largest Element in an Array 解答
    Merge k Sorted Lists 解答
    Median of Two Sorted Arrays 解答
    Maximal Square 解答
    Best Time to Buy and Sell Stock III 解答
    Best Time to Buy and Sell Stock II 解答
    Best Time to Buy and Sell Stock 解答
    Triangle 解答
    Unique Binary Search Trees II 解答
  • 原文地址:https://www.cnblogs.com/moomcake/p/9887307.html
Copyright © 2011-2022 走看看