POJ 3233 Matrix Power Series 矩阵幂级数

题面

查–看--题–目

Given a n × n n \times n n×n matrix A A A and a positive integer k k k, find the sum 给定一个 n × n n\times n n×n方阵,以及一个整数 k k k,计算下列级数
S = A + A 2 + A 3 + ⋯ + A k . S = A + A^2 + A^3 + \cdots + A^k. S=A+A2+A3++Ak.

  • The input contains exactly one test case. The first line of input contains three positive integers n ( n ≤ 30 ) , k ( k ≤ 1 0 9 ) n _{(n ≤ 30)}, k _{(k ≤ 10^9)} n(n30),k(k109) and m ( m < 1 0 4 ) m_{(m < 10^4)} m(m<104). Then follow n n n lines each containing n n n nonnegative integers below 32768 , 32768, 32768, giving A A A’s elements in row-major order.【输入】只包含一个案例。第一行输入 n , k , m n,k,m n,k,m,其中 m m m表示模数,三者以空格分割。下面 n n n行输入一个 n × n n\times n n×n的方阵,元素数值 ∈ [ 0 , 2 15 ) . \in[0,2^{15}). [0,215).
  • Output the elements of S S S modulo m m m in the same way as A A A is given.【输出】输出模 m m m意义下的矩阵 A A A的级数 S S S

分析

分治

  • 抛开矩阵来看这个式子,就是一个几何级数(等比数列之和)。
    完全有一个分式形式的求和公式,听说也可以做(在模意义下可以使用矩阵的逆改写其形式)
  • 可以考虑分治计算之:
  1. k 是 偶 数 k是偶数 k
    S ( n ) = A + A 2 + A 3 + ⋯ + A k = ( A + A 2 + ⋯ + A n / 2 ) + ( A n / 2 + 1 + A n / 2 + 2 + ⋯ + A n ) = ( A + 1 ) × ( A + A 2 + ⋯ + A n / 2 ) = ( A + 1 ) × S ( n 2 ) \begin{aligned}S(n) &= A + A^2 + A^3 + \cdots + A^k\\ &=(A + A^2 + \cdots + A^{n/2}) + (A^{n/2+1} + A^{n/2+2} +\cdots + A^n)\\ &=(A+1)\times(A + A^2 + \cdots + A^{n/2})\\ &=(A+1)\times S(\dfrac{n}{2})\\ \end{aligned} S(n)=A+A2+A3++Ak=(A+A2++An/2)+(An/2+1+An/2+2++An)=(A+1)×(A+A2++An/2)=(A+1)×S(2n)
  2. k 是 奇 数 k是奇数 k
  • 则有 k − 1 k-1 k1是偶数
  • 特殊的,对于 k = 1 k=1 k=1时,有 S ( 1 ) = A S(1) = A S(1)=A,作为递归出口即可

代码如下

inline Ma calc(Ma& A, int k) {
     
    if (k == 1)
        return A;
    Ma ans = calc(A, k >> 1);
    ans = ans + (A ^ (k >> 1)) * ans;
    if (k & 1) ans = ans + (A ^ k);
    return ans;
}

快速幂

  • 对于矩阵的高次幂,直接算显然无法承受
  • 使用快速幂优化
  • 代码见下方

代码

最终代码

#include 
#include 
#include 
using namespace std;

static const int N = 45;
int n, mod;

矩阵类

struct Ma {
     
    int a[N][N];

    Ma() {
     
        memset(a, 0, sizeof a);
    }

    inline void unit() {
     
        for (int i = 0; i < n; ++i)
            a[i][i] = 1;
    }

    Ma operator* (const Ma& B) const {
     
        Ma ans;
        for (int t = 0; t < n; ++t) {
     
            for (int i = 0; i < n; ++i) {
     
                int r = a[i][t];
                for (int j = 0; j < n; ++j) {
     
                    ans.a[i][j] = (ans.a[i][j] + r * B.a[t][j]) % mod;
                }
            }
        }
        return ans;
    }

    Ma operator^ (int n) {
     
        Ma ans;
        ans.unit();
        Ma A = *this;
        while (n) {
     
            if (n & 1) ans = ans * A;
            A = A * A;
            n >>= 1;
        }
        return ans;
    }

    Ma operator+ (const Ma& B) const {
     
        Ma ans = Ma();
        for (int i = 0; i < n; ++i) {
     
            for (int j = 0; j < n; ++j) {
     
                ans.a[i][j] = ( a[i][j] + B.a[i][j] + mod) % mod;
            }
        }
        return ans;
    }

    inline void show() {
     
        for (int i = 0; i < n; ++i) {
     
            for (int j = 0; j < n; ++j) {
     
                printf("%d ", a[i][j]);
            }
            putchar(10);
        }
    }
};

分治

inline Ma calc(Ma& A, int k) {
     
    if (k == 1) {
     
        return A;
    }
    Ma ans = calc(A, k >> 1);
    ans = ans + (A ^ (k >> 1)) * ans;
    if (k & 1) ans = ans + (A ^ k);
    return ans;
}

主函数

int main() {
     
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int k;
    scanf("%d%d%d", &n, &k, &mod);
    Ma A;
    for (int i = 0; i < n; ++i) {
     
        for (int j = 0; j < n; ++j) {
     
            scanf("%d", &A.a[i][j]);
            A.a[i][j] %= mod;
        }
    }

    A = calc(A, k);
    A.show();

    return 0;
}

细节

  • 反正我是错了很多次…

矩阵乘法取模

POJ 3233 Matrix Power Series 矩阵幂级数_第1张图片

POJ 3233 Matrix Power Series 矩阵幂级数_第2张图片

重载运算符

  • 不放图了,大概就是以后不会再用friend

哭哭

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