Loading

进阶区间 dp

序列dp&&区间dp

长度为 \(n\) 的合法括号序列有多少个?答案对 \(10^9 + 7\) 取模

\(f[i][j]\) 表示前 \(i\) 个括号里面,还有 \(j\) 个左括号没有匹配的合法序列的个数

转移

$ j \neq 0~~f[i][j + 1] = max(f[i - 1][j], f[i - 1][j + 1] + 1)$

\(j = 0~~ f[i][j + 1] = f[i - 1][j]\)

石子合并

\(f[i][j] = min(f[i][k] + f[k+1][j] + sum[j] - sum[i - 1])\)

\(Crasia Wachs\) 算法 ? ?

四边形不等式优化?!

\(LCS\) 计数(长度和个数)

\(a[i] \neq b[j]~~~~~f[i][j] = max(f[i - 1][j],f[i][j - 1])\)

\(a[i] = b[j] ~~~~f[i][j] = max(f[i - 1][j - 1] + 1, f[i - 1][j], f[i][j - 1])\)

\(lis\) 长度等于 \(lcs\) 个数

飞扬的小鸟poi2017

\(x\) 为上升的次数(即点击屏幕的次数),\(y\) 为下降的次数,则从起点到到点\(\left({a,b}\right)\) 时,满足

\(\begin{cases}x+y=a\\x-y=b\end{cases}\)

故有 \(x=\dfrac{a+b}{2}\)

利用这个性质和上一个柱子所在位置对这个位置的限制条件对到达这个柱子时的所能到达的高度范围进行确定,再利用柱子判断这个范围合不合法就好了

涂色

\(f[i][j]\) 表示 \([i, j]\) 涂成目标颜色所需要的次数,靠边界转移

如果 \(color[i - 1] = color[j + 1]\) 那么只需要涂一次就好了

\(f[i][j] = min(f[i + 1][j], f[i][j - 1])\)

否则

\(f[i][j] = min(f[i][k], f[k + 1][j])\)

CF1132F Clear the String

考虑右端点 \(r\) 和谁一起删掉,把它们可以看做一个字母

\(f[l][r] = f[l][k] + f[k + 1][r- 1]\)

注意区间的枚举顺序

大区间由小区间合并而来,所以应该先枚举小区间

判断其尾部,前面的应该是已知的状态所以应该从左向右枚举

RGB Sequence

\(n\) 个格子,要给它们染上红/蓝/绿中的一个颜色

\(m\) 个限制,形如 \((l,r,x)\) ,表示 \([l,r]\) 区间内出现的颜色种类的数量恰好为 \(x\)

solution

我们统计区间颜色的种类数的时候:记录前面序列中每种颜色的最后一次出现的位置,根据每种颜色最后出现的位置就可以判断这段区间出现的颜色的种类

所以 \(dp\) 设状态的时候就是基于这个设计的

\(a[i]\) 为第 \(i\) 个块上的颜色

\(f[i][j][k]\) \(j\) 为前面与 \(a[i]\) 不同的块最后一次出现的位置,\(k\) 为前面与 \(a[i]\)\(a[j]\) 都不同的块第一次出现的位置

根据所给的 \(M\) 条限制 \((l,r,x)\) 判断状态是否合法

\((r == i)\) 不合法的状态有:

  • \(x = 1\) 如果 \(l \leq j\) 就会出现两种情况,不合法
  • \(x = 2\) 如果 \(l \leq k|l > j\) ,会出现三种或者一种颜色,那么不合法
  • \(x = 3\) 如果 \(l > k\) 就会出现一种或者两种颜色,那么就不合法

转移

  • \(a[i + 1] = a[i]\) \(f[i + 1][j][k] = f[i][j][k]\)

  • \(a[i + 1] = a[j]\) \(f[i + 1][i][k] = f[i][j][k]\)

  • \(a[i + 1] = a[k]\) \(f[i + 1][i][j] = f[i][j][k]\)

收获: \(dp\) 状态设计特别妙,基于统计区间颜色不同方法,把 \(dp\) 状态设计为颜色最后一次出现的位置

P3592 [POI2015]MYJ

\(n\) 家洗车店从左往右排成一排,每家店都有一个正整数价格 \(p[i]\)\(m\) 个人要来消费,第 \(i\) 个人会驶过第 \(a[i]\) 个开始一直到第 \(b[i]\) 个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于 \(c[i]\),那么这个人就不洗车了。请给每家店指定一个价格,使得所有人花的钱的总和最大

\(1 \leq n\leq50,1\leq m\leq4000, 1\leq c_i\leq5*10^5\)

solution

不难发现\(c_i\) 的值对答案没有影响,所以先将 \(c_i\) 离散化

状态: \(f[i][j][k]\) 表示 \(i\)\(j\) 区间内最小值为 \(k\) 时的最大收益

转移:枚举区间的最小值所在的位置 \(x\)

\(f[i][j][k] = max(f[i][x - 1][y] + f[x + 1][j][z] + cost_x)(y\geq k, z \geq k)\)

\(cost_x\): 区间跨过 \(x\) ,并且在 \([i,j]\) 内所有人的花的钱之和

时间复杂度

\(O(n^3*m)\)

收获: 对信息离散化,根据题意设 \(dp\) 状态,题目中有影响的为区间的最小值,所以状态应该设置为区间最小值

string weigh

定义:字符串的重量为对所有出现了的字母,将其最后一次出现的位置减去第一次出现的位置减去第一次出现的位置加起来得到的数

定义:一个字符串是轻的,当且仅当它是所有同长度的字符串里重量最小的之一

选取 \(n\) 个轻的字符串,它们顺次相接,第 \(i\) 个字符串的长度是 \(L_i\) ,问最后字符串的重量最少是多少

\(n\leq 50~~L_i 100\)

solution

​ 考虑一个子串中出现的字母,存在四种情况

  • 这是它在总串中唯一一次出现
  • 这是它在总串中第一次出现(不是唯一一次出现)
  • 只是它在总串中最后一次出现(不是唯一一次出现)
  • 既不是第一次出现也不是最后一次出现

很明显,我们只需要考虑第二种和第三种情况就好了,所以对这两类进行设立状态 \(dp\)

将第二类的贡献设定为负的,第三类为正的,如果为第二类,\(dp\) 值就减去位置,如果是第三类 \(dp\) 值就加上位置

贪心考虑,将第二种情况放在后面,第三种情况放在前面,其他放在中间,只要知道每种情况出现的次数就可以得出这个子字符串对答案的贡献

\(dp\) 记下当前已经使用过的字母个数和已经不能再使用的字母的个数,枚举每个子串中各种情况的次数就好了

\(f[i][j][k]\) 表示到第 \(i\) 个子串,\(j\) 个已经出现一次的, \(k\) 个已经结束的

注意:如果枚举的子串中,最后一次出现的次数比前面第一次出现的字母多,就说明些字母在子串中自己已经匹配了,所以要单独考虑这些子串

fox flower shop

\(n*m\) 的网格,每个格子都写着 \(0,+1,-1\) 选择两个互不相交的矩阵,其中数字的和的绝对值不超过 \(k\) ,问绝对值的和最大是多少

\(n,m\leq50\)

solution

两个矩形绝对值的和可以拆成两个矩形分别的绝对值的和

枚举一条分割线(列或者行),\(f[i][x]\)\(i\) 行和为 \(x\) 的矩形的绝对值的和的最大值

\(g[i][y]\) 表示 \(i->n\) 行和为 \(y\) 的矩形的绝对值的和的最大值

转移: \(h[n][x + y] = max(f[i][x] + g[i + 1][y])(|x + y|\leq k)\)

\(i\) 是一定要枚举的,但要直接枚举 \(x\)\(y\), 显然会 \(T\),我们发现 \(x,y\) 是有限制条件的 \(|x + y| \leq k\) 展开这个式子会有 \(-k\leq x + y\leq k\) 得到 \(-y - k \leq x \leq k - y\),所以枚举 \(y\) 的时候用单调队列维护 \(x\) 就好了

最后答案就是 \(max(h[m][x],~~h[n][x])(|x| \leq k)\)

关于 \(f[i][x]\)\(g[i + 1][y]\) 的预处理??

收获: 卷积问题,枚举分割线,考虑把答案分割成两部分,最后把它们合并

planet of singles

有两个长度为 \(n\)\(01\)\(s,t\) 有三种操作

  • \(s\) 的一个 0 改为1, 代价为 \(t_0\)
  • \(s\) 的一个 1 改为0, 代价为 \(t_1\)
  • \(s\) 两个相邻的字符交换位置,代价为\(t_2\)
  • 求使得两串一样的最小花费

solution

关于第三种操作:

如果我们交换任意两个位置 \(i,j\) 上的数,按照常理代价应该为 \(2*|i - j - 1|*t_2\) 但实际的代价应该为 \(|i- j|*t_2\) 交换相邻的 \(1\)\(0\) 操作没有意义,所以有意义的交换一定是对逆序对总数产生影响的交换,交换 \(1\) 的时候对区间内与 \(0\) 生成的逆序对有影响,交换 \(0\) 对区间内 \(1\) 的逆序对有影响,因为 \(i\)\(j\) 也交换了一次,所以总的代价为 \(|i-j|*t_2\)

构造一个新串 \(c\) ,如果 \(t_i\) 为 1, \(t_i\) 串为 0, 则 \(c_i\) 串为 1;如果 \(s_i\) 串为 0, $ t_i$ 串为1,\(c_i\) 串为 \(0\),问题就转化成了在 \(c\) 中使得每个 \(0\) 与一个 \(1\) 匹配并且代价最小,并对匹配的交换 \(t_3\) 或者对两者都改变 \(t_0 + t_1\)

容易很久发现,对于一次交换,\(a, b , c, d\)

\(a\)\(b\) 交换、\(c\)\(d\) 交换和 \(a\)\(c\) 交换、\(b\)\(d\) 交换是等价的

所以对于两次交换:\((u_1, v_1),(u_2, v_2), u_1 < u_2\) 一定有 \(v_1 < u_2\) ,即交换不交叉,同时对于交换的 \(u,v\)\(\forall i \in (u,v)\) 一定是都是通过交换处理的(区间里面的进行更改操作,不如与端点进行交换,然后改变另一个端点更优)

考虑 \(dp\)\(dp[i][j]\) 表示 \([i,j]\) 区间内完成匹配的最小代价 (\([i,j]\)\(0\)\(1\) 的个数相等)

  • \(j\)\(i\) 如果进行前两次更改操作的话,就直接加上 \(t_1\)\(t_2\) 的代价就好了
  • \(i\)\(j\) 进行交换,所以 \([i,j]\) 区间内的所有匹配的都要交换, 那就要满足区间内 \(1\) 的个数等于 \(0\) 的个数,代价就是所有 \(\sum\)匹配的01之间的距离*t_2

怎么求区间内匹配的所有 \(0\)\(1\) 的距离和??

如果区间内所有 \(0\) 都在 \(1\) 的右侧,直接用所有 \(0\) 的位置的和减去所有 \(1\) 的位置的和

那么我们枚举一个 \(i\)\(j\) 交换, \(j\)\(0\) 并且 \(i\)\(j\) 左侧第一个满足条件区间 \([i,j]\) 中所有 \(0\) 都在 \(1\) 的右侧的点,那这段区间的代价就可以直接用所有 \(0\) 的位置减去 \(1\) 的位置求出来了,如果 \(j\)\(1\) 的话就反过来减就好了

为什么为 \(j\) 左侧第一个满足条件的?因为前面的点可以构成一个新的组合进行枚举

收获: 考虑问题的转化,以及对问题条件的分析;由使得两个字符串相同转化为使得一个新串得到匹配,以及对第三个条件的处理

P1758 [NOI2009] 管道取珠

有两条分支管道汇集成一条总管道,一条的分支管道有 \(n\) 个珠子,下面有 \(m\) 个珠子,每个珠子是黑色或者白色,每次从某个分支管道末端取出一个珠子,假设最后得到的不同序列一共有 \(T\) 种,有 \(a_i\) 种不同的取法,可以得到第 \(i\) 种序列,求

\(\sum^T_{i=1}a_i^2\)

solution

\(\sum^T_{i = 1}a_i\) 显然就是所有的情况:\(n + m \choose n\)

考虑 \(\sum^T_{i = 1} a_i^2\) 的集合意义

发现答案表示让两个人分别取珠,最后得到的序列相同的方案数之和

于是可以 \(DP\)\(f_{k,i,j}\) 表示两个人都取了 \(k\) 颗珠子,第一个人在上方水管中取了 \(i\) 颗,第二个人在上方水管中去了 \(j\) 颗,得到的序列相同的方案总数。枚举前一次两个人分别取得拿个管道里的珠子转移即可

复杂度 \(O(n^3)\)

posted @ 2021-05-03 21:36  Dita  阅读(154)  评论(0)    收藏  举报