首页 > 其他分享 >矩阵优化dp

矩阵优化dp

时间:2023-10-15 21:58:16浏览次数:38  
标签:Matrix fos res 矩阵 base bmatrix 优化 dp

都快csps了,还什么都不会的菜鱼(我估计着马上就可以改了这句话了,成了都快noip了

矩阵

我们要用矩阵优化dp,首先要知道矩阵是个什么东西(感觉其实可以不用知道)。

矩阵的很多定义啥的都可以选择去oi-wiki上去进行学习。很简单的一堆定义。读者自学不难,这里就不多赘述。

矩阵加法

就是将对应 \(A\) 和 \(B\) 两个矩阵对应位置相加。然后得到 \(C\) 这个矩阵。

矩阵乘法

这里大概讲一下矩阵乘法的原理:(突然学了,这里说的好像是内积,外积没见过用(逃)

image

我们会由一个 \(a \times b\) 的矩阵和一个 \(b \times c\) 的矩阵得到一个 \(a \times c\) 的矩阵。这个时候我们是将左边两个黄色的矩阵每一项相乘然后相加得到了右边矩阵的黄色位置,其他位置亦然,读者自想不难。

一个重要的性质:矩阵乘法是符合结合律的,这也是为什么我们可以用快速幂去优化dp

矩阵求逆

我们有时候会用到一个矩阵的逆矩阵,这个时候我们就要去思考如何计算出来这个逆矩阵。

我们通常是在我们的矩阵右边拼上一个单位矩阵,然后用高斯消元的方法,将左边的原矩阵,变成一个单位矩阵,此时我们右边得到的就是我们的原矩阵的逆矩阵。

矩阵除法

我们将我们要除以的矩阵转换为它的逆矩阵(类比逆元),这个时候再对他进行矩阵乘法。

矩阵求最大最小(这个名字是我自己取的)(貌似已经名算有主,叫做广义矩阵乘法)

感觉矩阵里面可能并没有这个操作,但是我们在优化dp的时候难免不会少了这种求最大最小的动规形式,所以就单独拎出来说一下,也就当作矩阵的一个基本运算吧(辉算?还是carp算)找到题目了再upd(逃

广义矩阵乘法的 \(A \times B = C\)为:

\[C_{i, j} = max_{k=1}^{n}(A_{i, k} + B_{k, j}) \]

广义矩阵乘法是具有结合律的,所以也可以用矩阵快速幂来进行优化,

先放个板子

之后再根据例题看怎么应用。

code
struct Matrix
{   
    ll a[N][N];

    inline void init() { memset(a, 0, sizeof a); }

    Matrix operator +(const Matrix &x) const 
    {
        Matrix res;

        fos(i, 0, N)
            fos(j, 0, N)
                res.a[i][j] = (a[i][j] + x.a[i][j]) % P;
        return res;
    }

    Matrix operator -(const Matrix &x) const
    {
        Matrix res;

        fos(i, 0, N - 1)
            fos(j, 0, N - 1)
                res.a[i][j] = (a[i][j] - x.a[i][j]) % P;

        return res;
    }

    Matrix operator *(const Matrix &x) const
    {
        Matrix res;
        fos(i, 0, N - 1)
            fos(k, 0, N - 1)
                fos(j, 0, N - 1) 
                    res.a[i][j] = (res.a[i][j] + (a[i][k] * x.a[k][j]) % P) % P;
        
        return res;
    }

    Matrix operator ^(ll k) const
    {
        Matrix ans, base;
        fos(i, 0, N - 1) res.a[i][i] = 1;
        fos(i, 0, N - 1)
            fos(j, 0,  N - 1) base.a[i][j] = a[i][j] % P;
        while(k)
        {
            if(k & 1) res = res * base;
            base = base * base; 
            k >>= 1;
        } 

        return res;
    }
} ans, base;

矩阵优化dp的适用范围

基本上就是对于一个线性递推式,我们构造一个答案矩阵,再构造一个转移矩阵,每次将这个转移矩阵进行快速幂,然后我们用答案矩阵去乘转移矩阵,具体就是一个快速幂的实现。

例题

举个很板的栗子。
斐波那契数列

我们都知道斐波那契数列里面有这个递推式

\[f_i = f_{i -1} + f _ {i - 2} \]

这个时候我们就可以用上面矩阵乘法的思路来进行求解:
step 1 : 构造一个答案矩阵 \(\begin{bmatrix} f_{1} & f_{2} & f_{3}\end{bmatrix}\)

step 2 : 我们还需要构造一个转移矩阵,这个转移矩阵就是依据我们的上面的线性递推式得出来的。 \(\begin{bmatrix} 0 & 0 & 0 \\ 1 & 0 & 1 \\ 0 & 1 & 1 \end{bmatrix}\)

step 3 : 接下来就是进行一个快速幂的计算。进行多少次,取决于你希望让这个答案的位置位于我们这个答案矩阵的第几个位子,若让我们的答案为答案矩阵的第二项,我们将进行 \(n - 2\) 次变换,然后得到 \(\begin{bmatrix} f_{n - 1} & f_{n} & f_{n + 1} \end{bmatrix}\)。

code
const ll N = 3, P =  1e9 + 7;

ll n;

struct Matrix
{
    ll a[N][N];

    Matrix operator *(const  Matrix &x) const
    {
        Matrix res;
		memset(res.a, 0, sizeof res.a);
        fos(i, 0, N - 1)  
            fos(k, 0, N - 1)
                fos(j, 0, N - 1)
                    res.a[i][j] = (res.a[i][j] + (a[i][k] * x.a[k][j]) % P) % P;
	
        return res;
    }
} ans, base;

inline void init()
{
    base.a[1][0] = base.a[1][2] = base.a[2][1] = base.a[2][2] = 1;
    ans.a[0][0] = ans.a[0][1] = 1, ans.a[0][2] = 2;
}

inline void qmi(ll k)
{
    while(k)
    {
        if(k & 1) ans = ans * base;
        base = base * base;
        k >>= 1;
    }
}

int main()
{   
    read(n); init();
    if(n <= 2) {puts("1"); return 0;} 
    ll k = n - 2;
	qmi(k);
	
	cout << ans.a[0][2] << endl;
    return 0;
}

但是我们发现,我们构造出来的转移矩阵中,第一横行都为 \(0\),所以我们就可以考虑,省去一维。

新的答案矩阵 \(\begin{bmatrix}f_1 & f_2\end{bmatrix}\),新的转移矩阵为 \(\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\)。剩下的代码读者自己实现不难。


T1

广义斐波那契数列

这个可以作为一个很好的练习题,既不难,又可以检验之前学会了没有。

这个时候我们知道了广义斐波那契数列的递推式:

\[f_{i} \gets p \times f_{i - 1} + q \times f_{i - 2} \]

还是和上面的步骤一样,构造矩阵,然后转移。

不难得出我们的答案矩阵为 \(\begin{bmatrix} f_{1} f_{2}\end{bmatrix}\) ,但是由于我们的递推式的不同,我们的转移矩阵将变成 \(\begin{bmatrix} 0 & q \\ 1 & p \end{bmatrix}\)

之后即是相同的矩阵快速幂。


数学作业

这个题目用来做一个提升感觉并不为过。

这个题目我们将会用到一种技巧,因为我们在转移的时候不是仅仅只有 dp 数组的转移,还要考虑带个常数,所以说我们会采取一个扩维的方法,单独扩出来一维,放上 1,然后转移我们那个拼接的数字。

之后就是我们的转移方程了(不会有人不会推吧):

\[f_{i} = f_{i-1} * 10 ^ {\lfloor {\log_{10} i} \rfloor + 1} + i \]

\[\begin{bmatrix} f_i \\ i \\ 1 \end{bmatrix} = \begin{bmatrix} f_{i - 1} \\ i - 1 \\ 1\end{bmatrix} \times \begin{bmatrix} 10 ^ {\lfloor\log_{10} i \rfloor} + 1 & 0 & 0 \\ 1 & 1 & 0 \\ 0 & 1 & 1\end{bmatrix} \]

标签:Matrix,fos,res,矩阵,base,bmatrix,优化,dp
From: https://www.cnblogs.com/carp-oier/p/17765387.html

相关文章

  • OpenGL入门——矩阵变换与坐标系统
    一、OpenGL的数学库GLM向量和矩阵的运算就不作说明了,直接介绍OpenGL中如何使用矩阵变换。GLM(官网:OpenGLMathematics(g-truc.net))是OpenGL Mathematics的缩写,它是一个只有头文件的库,也就是说只需包含对应的头文件就行了,不用链接和编译。把头文件的根目录复制到项目的includes......
  • 《算法学习专栏》—— DP问题之状态机模型
    2023年10月13日更新于2023年10月13日一、前言本栏,为状态机模型,题目主要来源日常,目前主要来源于Acwing的提高课。希望以后做到状态机的题目,也能加进来,不断完善。使用的分析方法均为闫式DP分析法。字臭。。。希望能用手写板慢慢写的好看。二、状态机模型2.1对于状态机的考虑......
  • ORCA优化器浅析——IMDRelation Storage type of a relation GP6与GP7对比
    如上图所示IMDRelation作为Interfaceforrelationsinthemetadatacache,其定义了Storagetypeofarelation表的存储类型,如下所示:enumErelstoragetype{ ErelstorageHeap, ErelstorageAppendOnlyCols, ErelstorageAppendOnlyRows, ErelstorageAppendOnlyParquet, E......
  • 自动批量将阿里云盘资源发布成WordPress文章带截图Python脚本(含正文 付费信息 下载地
    自动批量将阿里云盘资源发布成WordPress文章带截图Python脚本(含正文付费信息下载地址SEO等自动设置)自动批量将阿里云盘资源发布成WordPress文章带截图Python脚本(含正文付费信息下载地址SEO等自动设置)源码下载自动上传图片至WordPress站点,使用RestFulAPI批量发布文章,文章含......
  • 行列式与矩阵树定理
    定义定义矩阵的行列式:\[\detA=\sum_{\sigma}(-1)^{\tau(\sigma)}\prod_{i=1}^nA_{i\sigma_i}\]\(\tau(\sigma)\)是原排列的逆序对数。性质:若矩阵的某一行或某一列全为\(0\),则行列式为\(0\)。\(\detA=\detA^T\)。交换\(A\)的两行或两列,行列式取反。某一行或某一......
  • 2023_10_14_MYSQL_DAY_06_MYSQL优化的种类
    MYSQL优化的种类MYSQL的优化,是每一个程序员在做数据查询处理的时候,经常有的步骤那么SQL的优化有很多种,它可以是在硬件方面的,可以是在代码层面的,可以是在数据库方面的优化。下面就详细整理一下30种优化MYSQL的方案:1.在读表的时候,尽可能的避免全表扫描,合理的根据业务需求,在wher......
  • IPV6-NDP
    配置R1:<r1>displaycurrent-configuration [V200R003C00]#sysnamer1#snmp-agentlocal-engineid800007DB03000000000000snmp-agent #clocktimezoneChina-Standard-Timeminus08:00:00#portallocal-serverloadportalpage.zip#dropillegal-maca......
  • Linux内核进程管理与调度:策略优化与实践分析
    Linux内核进程管理与调度:策略优化与实践分析原创 李斌 嵌入式悦翔园 2023-05-0611:40 发表于上海关注★星标公众号,第一时间获取信息嵌入式悦翔园本公众号专注于嵌入式技术,包括但不限于STM32、Arduino、51单片机、物联网、Linux等编程学习笔记,同时,公众号内包含大量......
  • Codeforces Round 903 (Div. 3) E. Block Sequence(DP)
    CodeforcesRound903(Div.3)E.BlockSequence思路:设dp[i]为当i~n为完美的最少删除次数dp[n]=1,dp[n+1]=0;从后至前对于dp[i]更新若直接删除当前点,则为dp[i+1]+1若不删除则为min(dp[i+a[i]+1],dp[i]);i+a[i]+1为a[i]不能覆盖的位置#defineintlonglong#define......
  • Deep Learning —— 异步优化器 —— RMSpropAsync —— 异步RMSprop
       ============================================  代码地址:https://github.com/chainer/chainerrl/blob/master/chainerrl/optimizers/rmsprop_async.py defupdate_core_cpu(self,param):grad=param.gradifgradisNone:......