题解 UVA11149 Power of Matrix
简要题意:
给定一个
法一:暴力求解,单次时间复杂度
法二:分治,单次时间复杂度
我们可以按照分治的定义照猫画虎,将原式变成这样:
然后递归处理即可,分治部分的代码大概长这样: 1
2
3
4
5
6
7
8mat solve(mat bas, LL pos) { \\bas是原矩阵,pos代表当前k的大小
if (pos == 1) { return bas; }
mat s; clear(s);
for (int i = 0; i < n; ++i) { s.m[i][i] = 1; }
s = (s + qpow(bas, pos >> 1)) * solve(bas, pos >> 1);
if (pos & 1) { s = s + qpow(bas, pos); }
return s;
}
法三:倍增,单次时间复杂度
我们观察要求的这个式子,发现
不难发现在递推
如果题目高速我们
下面是参考代码(倍增过程在 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using namespace std;
namespace SHAWN {
LL n, k;
const int N = 41, M = 64, mod = 10;
struct mat { LL m[N][N]; };
mat f[M], s[M];
mat operator* (const mat &x, const mat &y) {
mat ans;
clear(ans);
for (int i = 0; i < n; ++i) {
for (int k = 0; k < n; ++k) {
if (x.m[i][k]) {
for (int j = 0; j < n; ++j) {
ans.m[i][j] = (ans.m[i][j] % mod + (x.m[i][k] * y.m[k][j]) % mod) % mod;
}
}
}
}
return ans;
}
mat operator+ (const mat &x, const mat &y) {
mat ans;
clear(ans);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
ans.m[i][j] = (x.m[i][j] + y.m[i][j]) % mod;
}
}
return ans;
}
mat qpow(mat a, LL b) {
mat z;
clear(z);
for (int i = 0; i < n; ++i) { z.m[i][i] = 1; }
for (int i = 0; i < n; ++i) {
if (b & 1) { z = z * a; }
a = a * a; b >>= 1;
}
return z;
}
void output(mat o) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << o.m[i][j] % mod;
if (j != n - 1) { cout << ' '; }
}
cout << '\n';
}
cout << '\n';
}
void solve() {
LL pos = 2, p = 1; // pos用来枚举2的次幂,p用来枚举2的幂次,pos的指数即为p,二者同加同减
while (pos <= k) {
f[p] = f[p - 1] * f[p - 1];
s[p] = s[p - 1] + s[p - 1] * f[p - 1];
pos <<= 1; ++p;
}
pos >>= 1; --p; // 第一次枚举完后肯定会超出k的范围,所以取上一次枚举到的幂
LL posback = pos; // posback表示拆分剩余的数时需要用到的2的次幂
mat po = f[p], ans = s[p]; // po表示当前已经枚举到的幂次,ans为答案,初始值为第一次枚举时枚举到最大的值
for (int i = p; i >= 0; --i) {
if (pos + posback <= k) {
ans = ans + po * s[i]; // 加到答案里
posback += pos;
po = po * f[i];
}
pos >>= 1; // pos的幂次要和p同步减一
}
output(ans); // 处理完输出
}
int work()
{
while (cin >> n >> k && n && k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> s[0].m[i][j];
f[0].m[i][j] = s[0].m[i][j] = s[0].m[i][j] % mod;
}
}
solve();
}
return 0;
}
}
signed int main() {
ios :: sync_with_stdio(false);
cin.tie(nullptr);
return SHAWN :: work();
}
ps. 特别提醒,UVa要注意输入和输出格式