Matrix
题目描述
对于两个 n n n 阶矩阵 A , B A,B A,B,定义矩阵乘法 C = A ∗ B C=A*B C=A∗B,则 C i j = ∑ k = 1 n A i k B k j C_{ij}=\sum_{k=1}^n{A_{ik}B_{kj}} Cij=∑k=1nAikBkj;定义矩阵加法 C = A + B C=A+B C=A+B,则 C i j = A i j + B i j C_{ij}=A_{ij}+B_{ij} Cij=Aij+Bij
定义矩阵的幂 A k = A ∗ A ∗ . . ∗ A ( 共 k 个 A ) A^k=A*A*..*A(共k个A) Ak=A∗A∗..∗A(共k个A)
给一个 n n n 阶矩阵 A A A 和整数 k k k,求 A + A 2 + A 3 + . . . + A k A+A^2+A^3+...+A^{k} A+A2+A3+...+Ak,答案对 998244353 998244353 998244353 取模
输入格式
第一行两个整数 n , k n,k n,k,表示矩阵大小以及 k k k
接下来 n n n 行,每行 n n n 个整数,表示 A i , j A_{i,j} Ai,j
1 ≤ n ≤ 150 , 1 ≤ k ≤ 1 0 9 , 0 ≤ A i j ≤ 1 0 9 1≤n≤150,1≤k≤10^9,0≤A_{ij}≤10^9 1≤n≤150,1≤k≤109,0≤Aij≤109
输出格式
n n n 行,每行 n n n 个整数,表示 A + A 2 + A 3 + . . . + A k A+A^2+A^3+...+A^{k} A+A2+A3+...+Ak 第 i i i 行第 j j j 列的值模 998244353 998244353 998244353 的结果
样例 #1
样例输入 #1
3 2
0 2 0
0 0 2
0 0 0
样例输出 #1
0 2 4
0 0 2
0 0 0
原题
思路
我们可以采用二分的思想解决这道题目。例如k=7时,
A
+
A
2
+
A
3
+
A
4
+
A
5
+
A
6
+
A
7
=
(
A
+
A
2
+
A
3
)
(
E
+
A
4
)
+
A
4
A+A^2+A^3+A^4+A^5+A^6+A^7=(A+A^2+A^3)(E+A^4)+A^4
A+A2+A3+A4+A5+A6+A7=(A+A2+A3)(E+A4)+A4。于是问题就转化为了求
A
+
A
2
+
A
3
A+A^2+A^3
A+A2+A3。可以进一步二分,即
A
+
A
2
+
A
3
=
A
(
A
+
A
2
)
+
A
2
A+A^2+A^3=A(A+A^2)+A^2
A+A2+A3=A(A+A2)+A2。那么我们就可以写一个函数递归求解。但是我们发现在每一步递归中还需要知道 A(k+1)/2 的值。首先想到的固然是矩阵快速幂求,但是这会把时间复杂度从O(n3logk)变为O(n3log2k),经过我的亲身TLE, 发现这是不行的。其实,我们可以把A(k+1)/2 的值放到每一步递归中维护。详见代码。
代码
#include <bits/stdc++.h>
using namespace std;
#define max_Heap(x) priority_queue<x, vector<x>, less<x>>
#define min_Heap(x) priority_queue<x, vector<x>, greater<x>>
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
const double PI = acos(-1);
#define mod 998244353
struct Mat
{
int m[151][151];
};
Mat a, e; // 读入矩阵和单位矩阵
ll n, p;
Mat Mul(Mat x, Mat y) // 矩阵乘
{
Mat c;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
c.m[i][j] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
{
c.m[i][j] = 1LL * c.m[i][j] % mod + 1LL * x.m[i][k] * y.m[k][j] % mod;
}
return c;
}
Mat Add(Mat x, Mat y) // 矩阵加
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
x.m[i][j] = (1LL * x.m[i][j] + y.m[i][j]) % mod;
}
}
return x;
}
// Mat Mat_Q_Pow(Mat x, ll y)
// {
// Mat ans = e;
// while (y)
// {
// if (y & 1)
// {
// ans = Mul(ans, x);
// }
// x = Mul(x, x);
// y >>= 1;
// }
// return ans;
// }
Mat A; // 递归过程中维护的Ai
Mat fuc(Mat x, ll k) // 二分递归求解
{
Mat tmp, y;
if (k == 1)
return x;
tmp = fuc(x, k / 2); // 递归
if (k & 1)
{
// y = Mat_Q_Pow(x, k / 2 + 1);
y = Mul(A, x);
A = Mul(x, Mul(A, A));
tmp = Add(Mul(y, tmp), tmp);
return Add(tmp, y);
}
else
{
// y = Mat_Q_Pow(x, k / 2);
y = A;
A = Mul(A, A);
return Add(Mul(y, tmp), tmp);
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> p;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> a.m[i][j];
A.m[i][j] = a.m[i][j];
}
}
for (int i = 1; i <= n; i++) // 初始化单位矩阵
{
e.m[i][i] = 1;
}
Mat ans = fuc(a, p);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (j != n)
cout << (ans.m[i][j] + mod) % mod << " ";
else
cout << (ans.m[i][j] + mod) % mod << "\n";
}
}
return 0;
}