Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 数论

  • 动态规划

    • 动态dp学习笔记
    • 广义矩阵乘法学习笔记
      • 魔改矩阵乘法
      • Height All the Same(Codeforces 630E)
    • 插头dp学习笔记
    • 斜率dp回顾
  • 暴力

  • 图论

  • 数据结构

  • 字符串

  • 几何

  • 博弈论

  • 其他

广义矩阵乘法学习笔记

# 前言

今天学动态dp的时候发现了这么一个东西

# 补充定理

max(a,min(b,c))=min(max(a,b),max(a,c))max(a,min(b,c))=min(max(a,b),max(a,c))max(a,min(b,c))=min(max(a,b),max(a,c))

min(a,max(b,c))=max(min(a,b),min(a,c))min(a,max(b,c))=max(min(a,b), min(a,c))min(a,max(b,c))=max(min(a,b),min(a,c))

# 矩阵乘法

由于A(AC)=(AA)CA(AC)=(AA)CA(AC)=(AA)C,即矩阵乘法满足结合律,因此,对于某种变换AAA,变换nnn次后对应的变换矩阵为AnA^nAn,则结果为AnCA^nCAnC,其中AnA^nAn用矩阵快速幂解决

因此对于形似dp[i][j]=∑k=1ndp[i−1][k]⋅G[k,j]dp[i][j]=\sum_{k=1}^{n}dp[i-1][k]\cdot G[k,j]dp[i][j]=∑k=1n​dp[i−1][k]⋅G[k,j]的题目我们可以用矩阵快速幂解决

# 魔改矩阵乘法

下面通过举例说明

假设现在要求f[i][j]=mink=1n(f[i−1][k]+G[k,j])f[i][j]=min_{k=1}^{n}(f[i-1][k]+G[k,j])f[i][j]=mink=1n​(f[i−1][k]+G[k,j])

我们重新定义矩阵乘法的第iii行jjj列元为C[i,j]=mink=1b(A[i,k]+B[k,j])C[i,j]=min_{k=1}^b(A[i,k]+B[k,j])C[i,j]=mink=1b​(A[i,k]+B[k,j])

下面证明其满足结合律

((AB)C)[i,j]=min⁡l=1c(min⁡k=1b(A[i,k]+B[k,l])+C[l,j])=min⁡k=1bmin⁡l=1c(A[i,k]+B[k,l]+C[l,j])=min⁡k=1b(A[i,k]+min⁡l=1c(B[k,l]+C[l,j]))=(A(BC))[i,j]\begin{aligned} (( A B ) C )[i, j] &=\min^{c} _{l=1}\left(\min _{k=1}^{b}( A [i, k]+ B [k, l])+ C [l, j]\right) \\ &=\min^{b} _{k=1} \min^{c} _{l=1}( A [i, k]+ B [k, l]+ C [l, j]) \\ &=\min^{b} _{k=1}\left( A [i, k]+\min _{l=1}^{c}( B [k, l]+ C [l, j])\right) \\ &=( A ( B C ))[i, j] \end{aligned}((AB)C)[i,j]​=l=1minc​(k=1minb​(A[i,k]+B[k,l])+C[l,j])=k=1minb​l=1minc​(A[i,k]+B[k,l]+C[l,j])=k=1minb​(A[i,k]+l=1minc​(B[k,l]+C[l,j]))=(A(BC))[i,j]​

因此可以用矩阵快速幂解决

注意,重新定义过后的矩阵乘法单位阵不一定是对角矩阵III

事实上,图论中的Flody最短路算法也可看作一种魔改版的矩阵乘法

# 例题

# Height All the Same(Codeforces 630E)

不带魔改的矩阵乘法。

这题当时不会做,老想着用组合数做(事实上组合数可做,代码更短)。

当n∗mn*mn∗m为奇数时,显然所有组合都可行,结果为(r−l+1)nm(r-l+1)^{nm}(r−l+1)nm

下面讨论当n∗mn*mn∗m为偶数的情况,由题解可知当且仅当奇数格个数为偶数是可行。

记OOO为可取奇数的数量,EEE为可取偶数的数量

使用矩阵乘法:考虑dpodd[i]dp_{odd}[i]dpodd​[i]代表iii个格子中有奇数个奇数格(即格子中的数为奇数)的选法,dpeven[i]dp_{even}[i]dpeven​[i]代表iii个格子中有偶数个奇数格的选法,那么有

dpodd[i]=dpodd[i−1]⋅E+dpeven[i−1]⋅Odp_{odd}[i] = dp_{odd}[i-1] \cdot E + dp_{even}[i-1] \cdot Odpodd​[i]=dpodd​[i−1]⋅E+dpeven​[i−1]⋅O

dpeven[i]=dpeven[i−1]⋅E+dpodd[i−1]⋅Odp_{even}[i] = dp_{even}[i-1] \cdot E + dp_{odd}[i-1] \cdot Odpeven​[i]=dpeven​[i−1]⋅E+dpodd​[i−1]⋅O

dpodd[1]=O,dpeven[1]=Edp_{odd}[1]=O,dp_{even}[1]=Edpodd​[1]=O,dpeven​[1]=E

最终答案为dpeven[nm]dp_{even}[nm]dpeven​[nm]

显然可以用矩阵乘法,矩阵快速幂可解!

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

# 参考资料

《矩阵乘法在信息学中的应用_余华程》

上次更新: 2021/02/24, 03:37:30
动态dp学习笔记
插头dp学习笔记

← 动态dp学习笔记 插头dp学习笔记→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式