poj3233 Matrix Power Series

Description

Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.

Input

The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.

Output

Output the elements of S modulo m in the same way as A is given.

Sample Input

2 2 4
0 1
1 1

Sample Output

1 2
2 3


【题意】:给出一个n * n矩阵A和一个正整数k,求 S = A + A2 + A3 + … + Ak

【题解】:以下是matrix67的题解:

这道题两次二分,相当经典。首先我们知道,A^i可以二分求出。然后我们需要对整个题目的数据规模k进行二分。比
如,当k=6时,有:
A + A^2 + A^3 + A^4 + A^5 + A^6 =(A + A^2 + A^3) + A^3*(A + A^2 + A^3)
应用这个式子后,规模k减小了一半。我们二分求出A^3后再递归地计算A + A^2 + A^3,即可得到原问题的答案。




代码:

#include <stdio.h>
#include <cstring>
int n,m,k;
const int N=31;
int ans[N][N],A[N][N];


void add(int a[][N],int b[][N]) {
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++) {
            a[i][j]+=b[i][j];
            if(a[i][j]>=m) a[i][j]%=m;
        }
}


void mul(int a[][N],int b[][N]) {
    int tmp[N][N];
    for(int i=0; i<n; i++) {
        for(int j=0; j<n; j++) {
            tmp[i][j]=0;
            for(int k=0; k<n; k++) {
                tmp[i][j]+=a[i][k]*b[k][j];
                if(tmp[i][j]>=m) tmp[i][j]%=m;
            }
        }
    }
    memcpy(a,tmp,sizeof(tmp));
}


void pow(int a[][N],int b[][N],int x) {
    int tmp[N][N];
    memcpy(tmp,b,sizeof(int)*N*N);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++) {
            if(i==j) a[i][j]=1;
            else a[i][j]=0;
        }
    while(x) {
        if(x&1)
            mul(a,tmp);
        mul(tmp,tmp);
        x>>=1;
    }
}


void mat_sum(int a[][N],int b[][N],int x) {
    int c[N][N],d[N][N];
    if(x==0) {
        memset(a,0,sizeof(int)*N*N);
        return ;
    }
    if(x==1) {
        memcpy(a,b,sizeof(int)*N*N);
        return ;
    }
    mat_sum(a,b,x>>1);
    pow(c,b,x>>1);
    memcpy(d,a,sizeof(int)*N*N);
    mul(a,c);
    add(a,d);
    if(x&1) {
        mul(c,c);
        mul(c,b);
        add(a,c);
    }
}


int main() {
    while(scanf("%d%d%d",&n,&k,&m)==3) {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d",&A[i][j]);
        mat_sum(ans,A,k);
        for(int i=0; i<n; i++) {
            printf("%d",ans[i][0]);
            for(int j=1; j<n; j++) {
                if(j<n-1) printf(" %d",ans[i][j]);
                else printf(" %d\n",ans[i][j]);
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值