• [动态dp]线段树维护转移矩阵


    背景:czy上课讲了新知识,从未见到过,总结一下。

    所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法。

    这类题目分为如下三个步骤:(都是对于常系数齐次递推问题)

    1先不考虑修改,不考虑区间,直接列出整个区间的dp方程。这个是基础,动态dp无论如何还是dp(这一步是一般是重点)

    2.列出转移矩阵。由于有很多修改操作,我们将数据集中在一起处理,还可以利用矩阵结合律,并且区间比较好提取,(找一段矩阵就好了),修改也方便。

    3.线段树维护矩阵。对于修改,我们就是在矩阵上进行修改,对于不同的题目,我们要用不同的修改方式,和记录手段。但是都是线段树一个节点维护的是这个区间内矩阵的信息。如矩阵乘积,矩阵和等等。线段树的区间优势,可以应对区间修改问题。

    T1:HDU5068

     

    这里,由于是单点修改,所以直接到叶子节点,修改后再pushup就可以了。

    线段树维护区间内矩阵乘积。

    T2:CF  Sasha and Array

    就是斐波那契数列。

    这里的可以原因是:提出B,因为矩阵右分配律,再提出一个M^x,还是矩阵右分配律。注意这里M^x,B是不能交换顺序的。但是M^x放在求和的前边乘,还是后边乘是无所谓的。因为都是M

    可以用左分配律,也可以用右分配律。

    其实代码不难想。

    1.laz标记应当建一个和t[4*N]一样的laz[4*N],这样,每个结构体只存一个矩阵a,不但节省空间,而且内置函数的矩阵乘法还方便,因为无论如何都转移到a矩阵,而不用考虑是a乘laz还是laz乘laz。

    2.数组越界了,被卡了很长时间。开a[3][3]就可以,没有发现的原因是,c++本地编译不会RE,放到CF上就会出现奇怪答案,而且莫名有的地方数组内的值就变了,比如说突然都变成0

    3.注释不要太多,以免掩盖正解,导致把laz 下放注释掉了。。。

    T3:

    本质不同:不一样。长度不同,或者长度一样对应位置数字不全一样。

    注意是子序列不是子串

    注意,为什么用f[i][0/1]?因为当最后一位不一样时,这两个子序列一定不一样,所以f[i-1][0]和f[i-1][1]中的每一个都是不一样的。

    并且,这还跟原数组数值0/1挂钩,很好联系上了。

    加的一个1是就取这一位,其实是之前每一个都多了一位,就没有了最初的长度为一的子序列。所以加上。

    也就是说,区间矩阵乘积结果的矩阵可以直接进行翻转,先翻再乘,和先乘再翻没区别。

    直接正常维护就好,加一个rev标记。

  • 相关阅读:
    Linux基础ls命令
    Linux基础tree命令
    Java银行调度系统
    Java交通灯系统
    Java反射
    Java基础IO流
    Java多线程
    Java集合框架
    Springmvc的一些属性功能
    JS
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9124511.html
Copyright © 2020-2023  润新知