最近做了些dp题,看看题目吧
对于我这种菜鸡可能比较有价值,大佬基本就别看了
题目传送门
放下Codevs的,感觉这里的数据规模比较适合。其他网站数据的太弱了
我们可以很轻易地想到,经过了一盏灯就一定要把它顺手关掉
那么可能我在经过某一段区间之后要回头,那么这一段区间我肯定要全部关掉
那么,我们令 f(i,j,0) 表示对于 [i,j] 这一段区间,我最后停留在点 i 最少要消耗的电功是多少;同理, f(i,j,1) 就表示停留在 j 点的时候了
我们只看 f(i,j,0) 的求解方式,因为 f(i,j,1) 和其类似
考虑最后停留在点 i 的话,可能从哪些点走过来
方向肯定是向左,所以我们只需考虑在 [i+1,j] 这段区间走过来即可
那么,只可能从 i+1 或者 j 点走过来
我们仔细想一想,最后的答案和时间的关系并没有那么大,我们只需要记录消耗了多少功即可
为什么? 我们可以这样理解,没有关灯的代价已经在电功里面了
那么我们可以得到转移方程:
时间复杂度? O(n2)
还是比较优秀的
主要算法:类似区间dp的思想
题目传送门
乍一看没什么思路? 起点不固定?? 两条路径是分开来的??
其实不用管起点的问题,只要考虑当前这个点是哪个人正在收
两条路径分开来怎么办?? 其实我们不用在意,类似于传纸条的做法
我们令 f(i,j,k,0) 表示在 (i,j) 这个格子上,当前两个人收集量之差为 k ,是第一个人的方案数; f(i,j,k,1) 同理,只是变成了第二个人而已
这种状态的思想和多米诺骨牌那道题差不多:
有 n 个多米诺骨牌,每个骨牌可以旋转。问怎么在使上下两部分之和的差的情况下,旋转的次数最少
令 f(i,j) 表示到第 i 个骨牌的时候,上面的和为 j 的最小旋转次数
当 up[i]≤j 时,令 x=f(i−1,j−up[i])
当 down[i]≤j 时,令 y=f(i−1,j−down[i])+1
注:如果不满足条件的话, x 或 y 的值等于 ∞
那么,转移方程就很简单了:
回归本题,那么剩下的就十分简单了
下面只写关于怎么求解 f(i,j,k,0) , f(i,j,k,1) 类似
设上一个人取完后的差为 x ,则 x=(k+num[i][j]))mod(K+1)
那么,我们可以得到以下转移方程:
时间复杂度? O(n2k)
但是我还是离奇地爆了空间和时间……
题目传送门
这很显然是一个树形结构,所以我们考虑树形dp
我们先令 f(i) 表示以 i 点的子树最大收益是多少
但是这似乎有一个问题:
可能当前收益为负数,但是和其他子树中和一下就变成正数了
所以这种dp是不可行的
那我们再考虑另一种思路:
我们令 f(i,j) 表示以 i 的子树,给 j 个用户的最大收益值
那么,最后的答案即为 k(f(1,k)≥0)
于是转移方程就可以得出来了:
f(i,j)=max(f(i,j−k)+f(soni,k)−(i,soni).v)
转移时间复杂度是 O(n) 的,具体证明我在此不加赘述
如果转移时 j 的范围不注意的话,复杂度会严重退化
所以这边要注意一下:
j 的范围为 [1,siz(i)] , siz(i) 表示 i 暂时访问到的那些儿子的子树中,有多少个叶节点,区别于 i 的子树大小
只有这样才会是 O(n) 的
题目传送门
似乎并不是特别好做?
因为是黑白间隔,所以并不是特别好判断某一块是不是符合条件
那么,我们是不是要对这个矩阵做一个小小的处理??
先对这个矩阵黑白染色,然后将白格中的数取反
换句话说,如果行加上列为偶数的话,就把这个格子中的数取反
然后如果说一开始的某个矩阵是黑白相间的,例如01,那么这个矩阵经过处理后会变成元素全部相等的矩阵
所以我们就可以用单调栈求出最大的元素全部相等的矩形
正方形直接dp即可
正确性显然吧……
因为相邻的格子颜色必须不同,而判断间隔并不那么好判断,所以我们考虑取反,就比较方便了
具体的做法我就不加赘述了,时间复杂度 O(n2)
题目传送门
很经典的题目了吧
典型的树上背包问题
可能读入有点坑,递归读入即可
其实我们还可以边读入边dp……(我就这么干的)
注意:走廊也算成一个点
我们来讲讲怎么dp
很明显,我们令 f(i,j) 表示在 i 号点,还有 j 个单位时间内最多能偷多少画
转移应该比较显然的吧……
题目传送门
因为这是一个森林,所以先将它并成一棵树,即0号点作为根
然后树形dp即可
这棵树是多叉树怎么办呢?
相对来说,我感觉多叉转二叉比较好,并且好写
啥意思? 就是把原本的儿子放在左子树,兄弟放在右子树
即变成了一棵二叉树
我们可以令 f(i,j) 表示以 i 为根的子树中,选择 j 门科目的最大总学分
那么,转移应该也蛮显然的
题目传送门
此题是比较简单的树形dp题
我们可以设 f(i) 表示 i 子树内的距离和, g(i) 表示 i 子树外的距离和
然后转移自己推一推就行了
反正我写了2个dfs