广义矩阵乘法学习笔记
# 前言
今天学动态dp的时候发现了这么一个东西
# 补充定理
# 矩阵乘法
由于,即矩阵乘法满足结合律,因此,对于某种变换,变换次后对应的变换矩阵为,则结果为,其中用矩阵快速幂解决
因此对于形似的题目我们可以用矩阵快速幂解决
# 魔改矩阵乘法
下面通过举例说明
假设现在要求
我们重新定义矩阵乘法的第行列元为
下面证明其满足结合律
因此可以用矩阵快速幂解决
注意,重新定义过后的矩阵乘法单位阵不一定是对角矩阵
事实上,图论中的Flody最短路算法也可看作一种魔改版的矩阵乘法
# 例题
# Height All the Same(Codeforces 630E)
不带魔改的矩阵乘法。
这题当时不会做,老想着用组合数做(事实上组合数可做,代码更短)。
当为奇数时,显然所有组合都可行,结果为
下面讨论当为偶数的情况,由题解可知当且仅当奇数格个数为偶数是可行。
记为可取奇数的数量,为可取偶数的数量
使用矩阵乘法:考虑代表个格子中有奇数个奇数格(即格子中的数为奇数)的选法,代表个格子中有偶数个奇数格的选法,那么有
最终答案为
显然可以用矩阵乘法,矩阵快速幂可解!
AC代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 998244353;
struct matrix{
ll val[2][2];
matrix(){memset(val, 0, sizeof val);}
matrix operator *(const matrix & m){
matrix result;
for(int i=0; i<2; i++){
for(int j=0; j<2; j++){
for(int k=0; k<2; k++)
result.val[i][j] = (result.val[i][j] + val[i][k] * m.val[k][j] % mod) % mod;
}
}
return result;
}
};
matrix qpow(matrix base, ll t){
matrix result;
result.val[0][0] = result.val[1][1] = 1;
while(t){
if(t & 1) result = result * base;
t >>= 1;
base = base * base;
}
return result;
}
ll qpow(ll base, ll t){
ll ret = 1;
while(t){
if(t & 1) ret = ret * base % mod;
t >>= 1;
base = base * base % mod;
}
return ret;
}
signed main(){
ll n, m, l, r;
cin >> n >> m >> l >> r;
if((n * m) & 1 == 1){
cout << (qpow(r - l + 1, n * m) % mod) << endl;
}else{
ll odd = (r + 1) / 2 - l / 2;
ll even = r / 2 - (l - 1) / 2;
matrix base;
base.val[0][0] = base.val[1][1] = even;
base.val[0][1] = base.val[1][0] = odd;
base = qpow(base, n * m - 1);
ll ans = base.val[1][0] * odd %mod + base.val[1][1] * even % mod;
cout << (ans % mod) << endl;
}
}
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
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
# 参考资料
《矩阵乘法在信息学中的应用_余华程》
上次更新: 2021/02/24, 03:37:30