题目

给定一个 $n \times n$  的矩阵 $A$ 和正整数 $k$ 和 $m$。求矩阵 $A$ 的幂的和。

$$S = A + A^2 + ... + A^k$$

输出 $S$ 的各个元素对 $M$ 取余后的结果($1 \leq n \leq 30, 1 \leq k \leq  10^9, 1 \leq M \leq 10^4$)。

分析

数据范围 $n$ 很小,$k$ 很大,不肯能逐一求得。

由于具有等比性质,

设  $S_k = I + A + ... + A^{k-1}$

则有

$$\begin{pmatrix} A^k\\  S_k \end{pmatrix} = \begin{pmatrix} A & 0\\  I & I \end{pmatrix} \begin{pmatrix} A^{k-1}\\  S_{k-1} \end{pmatrix} = \begin{pmatrix} A & 0\\  I & I \end{pmatrix}^k\begin{pmatrix} I\\  0 \end{pmatrix}$$

对这个新矩阵使用快速幂即可。

代码中的输出,使用了分块矩阵乘法的性质进行了简化。

#include<cstdio>
#include<cstring>
using namespace std; typedef long long ll;
struct matrix
{
int r, c;
int mat[][];
matrix(){
memset(mat, , sizeof(mat));
}
};
int n, k, p; matrix mul(matrix A, matrix B) //矩阵相乘
{
matrix ret;
ret.r = A.r; ret.c = B.c;
for(int i = ;i < A.r;i++)
for(int k = ;k < A.c;k++)
for(int j = ;j < B.c;j++)
{
ret.mat[i][j] = (ret.mat[i][j] + A.mat[i][k] * B.mat[k][j]) % p;
}
return ret;
} matrix mpow(matrix A, int n)
{
matrix ret;
ret.r = A.r; ret.c = A.c;
for(int i = ;i < ret.r;i++) ret.mat[i][i] = ;
while(n)
{
if(n & ) ret = mul(ret, A);
A = mul(A, A);
n >>= ;
}
return ret;
} int main()
{
scanf("%d%d%d", &n, &k, &p);
matrix a, b;
a.r = a.c = n;
for(int i = ;i < n;i++) for(int j = ;j < n;j++) scanf("%d", &a.mat[i][j]);
b.r = b.c = *n;
for(int i = ;i < n;i++)
{
for(int j = ;j < n;j++) b.mat[i][j] = a.mat[i][j];
b.mat[n+i][i] = b.mat[n+i][n+i] = ;
}
b = mpow(b, k+);
for(int i = ;i < n;i++)
for(int j = ;j < n;j++)
{
int tmp = b.mat[n+i][j] % p;
if(i == j) tmp = (tmp + p - ) % p;
printf("%d%c", tmp, j == n- ? '\n' : ' ');
}
}

还有一种经典的分治方法,

例如,

$A+A^2+A^3+A^4 = (A+A^2) + A^2(A + A^2)$,

$A+A^2+A^3+A^4+A^5 = (A+A^2) +A^3 +  A^3(A + A^2)$.

因此,分k的奇偶递归一下就可以了。

#include<cstdio>
#include<cstring>
using namespace std; typedef long long ll;
struct matrix
{
int r, c;
int mat[][];
matrix(){
memset(mat, , sizeof(mat));
}
};
int n, k, p; matrix mul(matrix A, matrix B) //矩阵相乘
{
matrix ret;
ret.r = A.r; ret.c = B.c;
for(int i = ;i < A.r;i++)
for(int k = ;k < A.c;k++)
for(int j = ;j < B.c;j++)
{
ret.mat[i][j] = (ret.mat[i][j] + A.mat[i][k] * B.mat[k][j]) % p;
}
return ret;
} matrix mpow(matrix A, int n)
{
matrix ret;
ret.r = A.r; ret.c = A.c;
for(int i = ;i < ret.r;i++) ret.mat[i][i] = ;
while(n)
{
if(n & ) ret = mul(ret, A);
A = mul(A, A);
n >>= ;
}
return ret;
} matrix add(matrix A, matrix B)
{
matrix ret;
ret.r = A.r; ret.c = A.c;
for(int i = ;i < A.r;i++)
for(int j = ;j < A.c;j++)
ret.mat[i][j] = (A.mat[i][j] + B.mat[i][j]) % p;
return ret;
} matrix sum(matrix x, int k) //A+A^2+..+A^k
{
if(k == ) return x;
matrix s = sum(x, k/);
if(k & )
{
matrix tmp = mpow(x, k/+);
return add(s, add(tmp, mul(tmp, s)));
}
else
{
matrix tmp = mpow(x, k/);
return add(s, mul(tmp, s));
}
} int main()
{
scanf("%d%d%d", &n, &k, &p);
matrix a, ans;
a.r = a.c = n;
for(int i = ;i < n;i++) for(int j = ;j < n;j++) scanf("%d", &a.mat[i][j]);
ans = sum(a, k);
for(int i = ;i < n;i++) for(int j = ;j < n;j++) printf("%d%c", ans.mat[i][j], j == n- ? '\n' : ' ');
}

这个时间复杂度咋算啊?知道的大犇请留言。

参考链接:

1. https://blog.csdn.net/rowanhaoa/article/details/21023599

2. https://blog.csdn.net/scf0920/article/details/39345197

最新文章

  1. .NET不可变集合已经正式发布
  2. Python之路【第四篇补充】:面向对象初识和总结回顾
  3. HDU 5145 NPY and girls 莫队+逆元
  4. codeforces 361 D - Friends and Subsequences
  5. dwr2反推
  6. linux磁盘设备知识
  7. wpa_cli 连接 wifi
  8. C语言+ODBC+SQL 连接
  9. 【转】单双精度浮点数的IEEE标准格式
  10. unix c 07
  11. relative、absolute和float
  12. 关于泛型中&lt;T extends comparable&gt;的理解
  13. Java并发之synchronized关键字
  14. 02 . 处理axios的三个问题 :设置基路径/axios挂载到vue原型/请求时自动携带token
  15. maven中target不能访问
  16. 关于php下的ajax赋值传值的调试
  17. 几何概型 uva11722
  18. Java基础【冒泡、选择排序、二分查找】
  19. glob获取指定目录下的东西+更改工作目录
  20. winform 之控件ListView

热门文章

  1. Qt去掉treeview项的焦点虚线
  2. redhat7.6Linux安装Oracle19C完整版教程
  3. 【翻译】在GitHub上通过星级评估排名前10的最受欢迎的开源Delphi项目
  4. ASP.NET MVC请求参数字符串之区分空与NULL
  5. Luogu4827 Crash的文明世界 组合、树形DP
  6. 9 同时搜索多个index,或多个type
  7. 线程池ThreadPool实战
  8. 并发编程之Java锁
  9. 学了python能干什么
  10. 深入理解JVM(二)--对象的创建