POJ3233

本文介绍了一种解决大规模矩阵幂级数求和问题的方法,通过观察规律将问题转化为更小规模的问题,并利用矩阵快速幂进行高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Matrix Power Series
Time Limit: 3000MS Memory Limit: 131072K
Total Submissions: 26191 Accepted: 10773

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
思路:因为S=A+A^2+A^3+...+A^K。但是K有1e9那么多。直接写肯定不行,然后我就想到要用每次提取出来一个A,然后递归回去算S,然后1e9还是不行,最后我推K=4的情况,S可以写成S=A+A^2+A^2(A+A^2)。而K=5时,S=A+A^2+A^3+A^3(A+A^2)。然后我发现每次都是那这个k分一半向下推,最后开递归回来求出来S即可。**疼的是写的时候忘了矩阵快速幂的重载*来实现矩阵相乘,然后就老老实实的打了函数。手残把奇数的情况打错了,比赛后1分钟才找打bug,然后就A了
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<map>
#define inf 0x3f3f3f3f
#define ll long long
#define maxx 5000000
using namespace std;
int n,k,m;
struct node
{
    int x[40][40];
}st;
node mul(node a,node b)
{
  node c;
  memset(c.x,0,sizeof(c.x));
  for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
          for(int k=1;k<=n;k++)
             c.x[i][j]=(c.x[i][j]+a.x[i][k]*b.x[k][j])%m;
  return c;
}
node pow(int u,node s)
{
    node c;
    memset(c.x,0,sizeof(c.x));
    for(int i=1;i<=n;i++)
        c.x[i][i]=1;
    while(u)
    {
        if(u%2==1)
            c=mul(c,s);
        u=u/2;
        s=mul(s,s);
    }
    return c;
}
node add(node a,node b)
{
    node temp;
    memset(temp.x,0,sizeof(temp.x));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            temp.x[i][j]=(a.x[i][j]+b.x[i][j])%m;
        }
    }
    return temp;
}
node sum(node ans,int kk)
{
    node temp,res;
    if(kk==1)
        return ans;
    temp=sum(ans,kk/2);
    if(kk%2==0)
    {
        res=pow(kk/2,ans);
        return add(mul(res,temp),temp);
    }
    else
    {
        res=pow(kk/2+1,ans);
        temp=add(mul(res,temp),temp);
        return add(temp,res);
    }
}
int main()
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&st.x[i][j]);
    node ans=sum(st,k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(j!=1) printf(" ");
            printf("%d",ans.x[i][j]%m);
        }
        printf("\n");
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值