Matrix Power Series【矩阵乘法】

>Link

POJ 3233


>Description

给出一个 n ∗ n n*n nn的矩阵 A A A,求出模 m m m的情况下 S n = A + A 1 + A 2 + . . . + A n S_n=A+A^1+A^2+...+A^n Sn=A+A1+A2+...+An


>解题思路

我们先考虑不是矩阵的情况,很容易推出求 s n s_n sn如下
[ a n − 1 s n − 2 ] → [ a n ( a n − 1 ∗ a ) s n − 1 ( s n − 2 + a n − 1 ) ] \begin{bmatrix} a^{n-1} & s_{n-2} \end{bmatrix} → \begin{bmatrix} a^n(a^{n-1}*a) & s_{n-1}(s_{n-2}+a^{n-1}) \end{bmatrix} [an1sn2][an(an1a)sn1(sn2+an1)]

所以 B B B矩阵应为 [ a 1 0 1 ] \begin{bmatrix} a &1 \\ 0 & 1 \end{bmatrix} [a011]

但是 a a a s s s实际上是矩阵,我们要求的是
[ A n − 1 S n − 2 ] → [ A n ( A n − 1 ∗ A ) S n − 1 ( S n − 2 + A n − 1 ) ] \begin{bmatrix} A^{n-1} & S_{n-2} \end{bmatrix} → \begin{bmatrix} A^n(A^{n-1}*A) & S_{n-1}(S_{n-2}+A^{n-1}) \end{bmatrix} [An1Sn2][An(An1A)Sn1(Sn2+An1)]
其实可以把 B B B矩阵扩大,也就是把 a a a 1 1 1 0 0 0置换成等价的 n ∗ n n*n nn大小的 X X X矩阵

a:正常操作, A ∗ X = A 2 A*X=A^2 AX=A2,所以 X X X A A A相同
1:一个矩阵乘上另一个矩阵 X X X与原本的相同,可推出 X X X矩阵的对角线为1,其余全为0
0:一个矩阵乘上一个矩阵为0,所以 X X X矩阵为全为0的矩阵

最后加进去, B B B矩阵变成:
[ [ a 1 , 1 a 1 , 2 . . . . . . . . . . . . . . . . . . a n , n ] [ 1 0 . . . 0 1 . . . 0 . . . 1 ] [ 0 0 0 . . . . . . . . . 0 0 0 ] [ 1 0 . . . 0 1 . . . 0 . . . 1 ] ] \begin{bmatrix} \begin{bmatrix} a_{1,1} & a_{1,2} &... \\ ...& ... &... \\ ... &... & a_{n,n} \end{bmatrix} & \begin{bmatrix} 1 & 0 &... \\ 0 &1 &... \\ 0&... & 1 \end{bmatrix}\\ \begin{bmatrix} 0 &0 &0 \\ ... & ... & ...\\ 0 &0 & 0 \end{bmatrix} & \begin{bmatrix} 1 & 0 &... \\ 0 &1 &... \\ 0&... & 1 \end{bmatrix} \end{bmatrix} a1,1......a1,2............an,n0...00...00...010001.........110001.........1


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

struct matrix
{
	int x, y;
	LL a[70][70];
} A, B, ans;
LL m;

matrix operator *(matrix a, matrix b)
{
	matrix c;
	c.x = a.x, c.y = b.y;
	for (int i = 1; i <= c.x; i++)
	  for (int j = 1; j <= c.y; j++) c.a[i][j] = 0;
	for (int k = 1; k <= a.y; k++)
	  for (int i = 1; i <= c.x; i++)
	    for (int j = 1; j <= c.y; j++)
	      c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j] % m) % m;
	return c;
}
void power (LL k)
{
	if (k == 1) {B = A; return;}
	power (k >> 1);
	B = B * B;
	if (k & 1) B = B * A;
}

int main()
{
	int n;
	LL k;
	scanf ("%d%lld%lld", &n, &k, &m);
	ans.x = n, ans.y = 2 * n;
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= n; j++)
	   scanf ("%lld", &ans.a[i][j]), ans.a[i][j] %= m;
	A.x = A.y = 2 * n;
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= n; j++) A.a[i][j] = ans.a[i][j];
	for (int i = 1; i <= n; i++)
	  A.a[i][i + n] = A.a[i + n][i + n] = 1;
	power (k);
	ans = ans * B;
	for (int i = 1; i <= n; i++)
	{
		for (int j = n + 1; j <= 2 * n; j++)
		  printf ("%lld ", ans.a[i][j]);
		printf ("\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值