[poj 3233]Matrix Power Series --- 构造 + 矩阵快速幂

传送门:poj3233


题目大意

给定一个 n × n n \times n n×n的矩阵 A A A,求矩阵 S S S,其中 S = A + A 2 + ⋯ + A k S = A + A^2 + \cdots + A^k S=A+A2++Ak,且对 m m m取模.


分析

乍一看,是个等比数列求和,然后扯上除法、逆元,然后 … \dots 就没有然后了,可以直接弃疗了.
  对此不得不换个思路,考虑一下构造递推式.
  由秦九韶算法可知 S i = A ∗ S i − 1 + A S_i = A * S_{i - 1} + A Si=ASi1+A,于是可以考虑像fibonacci那样构造一个辅助矩阵来优化递推
  于是就有了如下的式子:
[ S i A ] × [ A O I I ] = [ S i + 1 A ] \begin{bmatrix} S_i & A \end{bmatrix} \times \begin{bmatrix} A & O\\ I & I\end{bmatrix}= \begin{bmatrix} S_{i+1}& A \end{bmatrix} [SiA]×[AIOI]=[Si+1A]
    注: I I I为单位矩阵, O O O为零矩阵
  因此直接快速幂即可
  PS:网上也有直接自乘的,但其实差不多( S 1 = A S_1 = A S1=A)


代码

#include <cstdio>
#include <cstdlib>

#define IL inline

using namespace std;

IL int read()
{
    int sum = 0;
    bool k = 1;
    char c = getchar();
    for(;'0' > c || c > '9'; c = getchar())
    if(c == '-')
        k = 0;
    for(;'0' <= c && c <= '9'; c = getchar())
        sum = sum * 10 + (c - '0');
    return k ? sum : -sum;
}

typedef long long ll;

int mo;

struct matrix
{   
    int n, m;
    ll s[65][65];
    
    IL matrix(int n_ = 0, int m_ = 0)
    {
        n = n_; m = m_;
        for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            s[i][j] = 0;
    }
    
    IL matrix operator * (const matrix &b)
    {
        matrix c(n, b.m);
        for(int i = 1; i <= n; ++i)
        for(int k = 1; k <= m; ++k)
        if(s[i][k])
        for(int j = 1; j <= b.m; ++j)
        if(b.s[k][j])
        {
            c.s[i][j] += s[i][k] * b.s[k][j] % mo;
            if(c.s[i][j] >= mo) c.s[i][j] -= mo;
        }
        return c;
    }
    
    IL void out()
    {
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n; ++j)
                printf("%lld ", s[i][j]);
            printf("\n");
        }
    }
}a, b;

IL matrix power(matrix x, int t)
{
    matrix sum(x.n, x.m);
    
    for(int i = 1; i <= x.n; ++i) sum.s[i][i] = 1;
    
    for(; t; t >>= 1)
    {
        if(t & 1) sum = sum * x;
        x = x * x;
    }
    return sum;
}


int main()
{
    int n = read(), k = read(); 
    mo = read();
    
    a.n = n; b.n = b.m = a.m = (n << 1);
    
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= n; ++j)
            a.s[i][j] = a.s[i][j + n] = b.s[i][j] = read();
        b.s[i + n][i] = b.s[i + n][i + n] = 1;
    }
    
    if(k == 1) a.out(); else (a * power(b, k - 1)).out();
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值