[模板]矩陣快速冪(以hdu1757爲例

hdu1757 A Simple Math Problem
題意:
題目梗概給出函數式和限制條件
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .
輸入k(k<2*10^9)和m(m<10^5),輸出f(k)%m的結果
思路:

很明顯的矩陣乘法

a0 a1 a2 a3 a4 a5 a6 a7 a8 a9
1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 1 0

*

f(x-1)
f(x-2)
f(x-3)
f(x-4)
f(x-5)
f(x-6)
f(x-7)
f(x-8)
f(x-9)
f(x-10)

=

f(x)
f(x-1)
f(x-2)
f(x-3)
f(x-4)
f(x-5)
f(x-6)
f(x-7)
f(x-8)
f(x-9)

所以我們只需求上面(10x10)矩陣的(n-9)次冪,再乘以(10x1)(f(9)~f(0))的矩陣即可

(10x1) = 

9
8
7
6
5
4
3
2
1
0
公式 = (10x10)^n*(10x1)

代碼:

/**************************************************************
    Problem: HDU_1757
    User: soundwave
    Language: C++
    Result: Accepted
    Time: 0ms
    Memory: 1584KB
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <stdio.h>
#include <vector>

using namespace std;
typedef vector<int> Vint;
typedef vector<Vint> VVint;
typedef __int64 LL;
int MOD;
//矩陣乘法
VVint calc(VVint &A, VVint &B){
    VVint C(A.size(), Vint(A.size()));
    for(int i=0; i<A.size(); i++)
    for(int j=0; j<B[0].size(); j++)
    for(int k=0; k<B.size(); k++)
        C[i][j]  = (C[i][j] + (A[i][k]*B[k][j])%MOD) % MOD;
    return C;
}
//二分快速冪
VVint my_pow(VVint A, LL c){
    VVint B(A.size(),Vint(A.size()));
    for(int i=0; i<A.size(); i++)
        B[i][i] = 1;
    if(c == 1) return A;
    while(c>0){
        if(c&1) B = calc(B,A);
        A = calc(A,A);
        c>>=1;
    }
    return B;
}
int main(){
    LL k;
    while(~scanf("%I64d%d", &k, &MOD)){
        VVint A(10,Vint(10));
        Vint B(10);
        for(int i=0; i<10; i++)
            scanf("%d", &B[i]);
        if(k < 10) {printf("%I64d\n", k); continue;}
        for(int i=0; i<10; i++)
            A[0][i] = B[i];
        for(int i=1; i<10; i++)
            A[i][i-1] = 1;
        A = my_pow(A,k-9);
        k = 0;
        for(int i=0; i<9; i++)
            k = (k + (A[0][i]*(9-i))%MOD) % MOD;
        printf("%I64d\n", k);
    }
    return 0;
}
/*
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
-------------------
45
104
*/

反思:

最重要的是求出遞推關係來,然後轉化爲矩陣


發佈了76 篇原創文章 · 獲贊 106 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章