1. 程式人生 > >HDU 5015 233 Matrix 矩陣快速冪

HDU 5015 233 Matrix 矩陣快速冪

題意就是

現在有一個矩陣a,矩陣的第一行和第一列(出了a[0][0]) 給你, 讓你求a[n][m]

第一行是 a[0][1] = 233 , a[0][2] = 2333 , a[0][i] = a[0][i-1] * 10 + 3

a[i][j] = a[i-1][j] + a[i][j-1]

看題目:應該是矩陣快速冪了

舉個例子:

輸入:

3 1

23 47 16

我們手推一下a[3][1]

\begin{pmatrix} a[0][0] & 233 \\ a[1][0] & a[1][1] \\ a[2][0] & a[2][1] \\ a[3][0] & a[3][1] \end{pmatrix}\quad =\quad \begin{pmatrix} a[0][0] & 233 \\ 23 & 23\quad +\quad 233 \\ 47 & 47\quad +\quad 23\quad +\quad 233 \\ 16 & 16\quad +\quad 47\quad +\quad 23\quad +\quad 233 \end{pmatrix}

那a[1][2] =  2333 + 23 + 233

所以我們初始矩陣是一個 (1)列(n +2)行的矩陣

當n是3的時候 初始矩陣為

\begin{pmatrix} 23 & a[1][0] & a[2][0] & a[3][0] & 3 \end{pmatrix}

然後用來快速冪的矩陣為

\begin{pmatrix} 10 & 10 & 10 & 10 & 0 \\ 0 & 1 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 1 & 1 & 1 & 1 & 1 \end{pmatrix}

n為3的時候 m=1的時候

\begin{pmatrix} 23 & a[1][0] & a[2][0] & a[3][0] & 3 \end{pmatrix}\begin{pmatrix} 10 & 10 & 10 & 10 & 0 \\ 0 & 1 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 1 & 1 & 1 & 1 & 1 \end{pmatrix}\quad =\quad \begin{pmatrix} 233 & a[1][1] & a[2][1] & a[3][1] & 3 \end{pmatrix}

然後就是愉快的擼程式碼了

//
//  HDU5015 - 233Matrix.cpp
//  數論
//
//  Created by Terry on 2018/10/1.
//  Copyright © 2018年 Terry. All rights reserved.
//

#include <stdio.h>
typedef long long LL;
long long read(){
    long long x = 0, f = 1;
    char ch=getchar();
    while(ch < '0' || ch > '9'){if(ch=='-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
const int maxn = 12;
const long long mod = 10000007;
struct Matrix{
    long long m[maxn][maxn];
}unit;
long long int N, M;
Matrix operator * (Matrix a, Matrix b){
    Matrix ret;
    LL x;
    long long int n = N + 2;  // [0  -  N+1][0  -  N+1]
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            x = 0;
            for(int k = 0; k < n; ++k){
                x += ((LL)a.m[i][k] * b.m[k][j]) % mod;
            }
            ret.m[i][j] = (x) % mod;
        }
    }
    return ret;
}
void init_unit(){
    // 單位矩陣
    for(int i = 0; i < maxn; ++i){
        unit.m[i][i] = 1;
    }
}
Matrix pow_mat(Matrix a, LL n){
    Matrix ans = unit;
    while (n) {
        if(n & 1){
            ans = ans * a;
        }
        a = a * a;
        n >>= 1;
    }
    return ans;
}
int main(){
    init_unit();
    while (scanf("%lld%lld", &N, &M) != EOF) {
        Matrix ans, a;
        ans.m[0][0] = 23;
        for(int i = 1; i <= N; ++i){
            ans.m[0][i] = read();
        }
        ans.m[0][N + 1] = 3;
        
        // 構造快速冪用的矩陣
        long long int x = N + 1;
        for(int i = 0; i <= x; i++){
            for(int j = 0; j <= x; j++){
                a.m[i][j] = 0;
            }
        }
        for(int i = 0; i < x; i++){
            a.m[0][i] = 10;
            a.m[x][i] = 1;
        }
        a.m[x][x] = 1;
        
        for(int i = 1; i < x; i++){
            for(int j = 1; j <= i; j++){
                //printf("%d %d\n", j, i);
                a.m[j][i] = 1;
            }
        }
        // 求a[n][m]
        a = pow_mat(a, M);
        
        ans = ans * a;
        printf("%lld\n", ans.m[0][N] % mod);
    }
    return 0;
}