刷题系列——区间 dp

区间 dp 通过合并区间实现。若设计的状态空间较大考虑离散化

状态令 f i , j f_{i,j} 为一个区间的最优值,特定情况下加上一维。转移通常为 O ( n 2 ) O(n^2) ,如果是环,先断环为链。

P1005 矩阵取数游戏

每次取边缘值。

边缘值,意味着?余下能取的数还是一个区间。而对于每一行是独立的。

f i , j = max { f i 1 , j + a i 1 × 2 m j + i 1 , f i , j + 1 + a j + 1 × 2 m j + i 1 } f_{i,j} = \max \{f_{i-1, j} + a_{i-1} \times 2 ^{m - j + i - 1}, f_{i, j +1} + a_{j+1} \times 2 ^{m - j + i - 1} \}

高精不说,注意区间 dp 不存在空区间,所以枚举长度为一的区间模拟最终删除。

CF1114D Flood Fill

有一个长度为 n n 的序列,定义 [ i , j ] [i,j] 为联通块当且仅当 [ i , j ] [i,j] 内的元素为同一颜色。每次可以将一个联通块的颜色染成另一个颜色,求最少染多少次才能让 [ 1 , n ] [1,n] 是一个联通块。

先将相同的颜色成一个元素。状态转移为

f i , j = f i + 1 , j 1 + 1 ( i = j ) f_{i,j} = f_{i + 1, j - 1} + 1\quad (i = j)

f i , j = m a x { f i + 1 , j , f i , j 1 } + 1 ( i j ) f_{i,j} = max \{f_{i + 1, j}, f_{i, j-1} \} + 1 \quad (i \not= j)

P1220 关路灯

n n 盏灯,每盏灯都有功率,老张在第 i i 盏灯前。老张每秒可以从一个灯移动到与它相邻的灯,关掉一个灯不用时间。问最少消耗的电功率。

因为关灯不用时间,所以路过的灯都顺手关掉,意味着关掉 [ i , j ] [i,j] 的灯最后位置不在 i i 就在 j j 。设 f i , j , 0 f_{i,j,0} 为关掉了 [ i , j ] [i,j] 灯,停留在 i i 上最小总电功, f i , j , 1 f_{i,j,1} 为停留在 j j 上的最小总电功。对于一个 [ i , j ] [i,j] ,如果最后在 i i ,可能是从 i 1 i-1 走来的,也有可能是从 j j 掉头回来的,求最小值即可。对于 j j 同理。先前缀和预处理 s u m sum

f i , j , 0 = m i n f i + 1 , j , 0 + ( a i + 1 a i ) × ( s u m n + s u m i s u m j ) ,   f i + 1 , j , 1 + ( a j a i ) × ( s u m n + s u m i s u m j ) f_{i,j,0} = min { f_{i+1,j,0} + (a_{i+1} - a_i) \times (sum_n + sum_i - sum_j), \ f_{i+1,j,1} + (a_j - a_i) \times (sum_n + sum_i - sum_j)} \quad

f i , j , 1 = m i n f i , j 1 , 0 + ( a j a i ) × ( s u m n + s u m i 1 s u m j 1 ) ,   f i , j 1 , 1 + ( a j a j 1 ) × ( s u m n + s u m i 1 s u m j 1 ) f_{i,j,1} = min {f_{i,j-1,0} + (a_j - a_i) \times (sum_n + sum_{i-1} - sum_{j-1}), \ f_{i,j-1,1} + (a_j - a_{j-1}) \times (sum_n + sum_{i-1} - sum_{j-1}) }
当然,若将灯坐标的范围扩大,可以离散化。

P1880 石子合并

一些数排成一环,可以将相邻的两个数合并,权值为两数之和,求合并为一个数的最大权值和最小权值。

只考虑最大权值,先将长度为 n n 的环切成长度为 n × 2 n \times 2 的链。设 f l , r f_{l,r} 为将 [ l , r ] [l,r] 的数合并为一堆的最大权值,可以枚举一个分界点,用前缀和预处理。dp 完后扫一遍取最大值即可。转移方程为

f l , r = m a x { f l , k [ l , r ) + f k + 1 , r + s u m r s u m l 1 } f_{l,r} = max \{ f_{l,k \in [l,r)} + f_{k + 1, r} + sum_r - sum_{l-1} \}

POJ 2955 Brackets

给定一个括号序列,求最长合法括号子序列的长度。合法的括号序列满足下列条件

  1. 空的括号序列是合法的。
  2. 如果一个括号序列 s 是合法的,那么 (s) 和 [s] 都是合法的。
  3. 如果两个括号序列 a 和 b 都是合法的,那么 ab 也是合法的。
  4. 其他的括号序列都是不合法的。

f l , r f_{l,r} [ l , r ] [l,r] 的最大匹配数。

for (int i = 1; i < n; i++)

    for (int l = 0; l < n - i; l++){
        int r = l + i;
        if (s[l] == '(' && s[r] == ')' || s[l] == '[' && s[r] == ']') 
            dp[l][r] = dp[l + 1][r - 1] + 2;
        for (int j = l; j < r; j++)
            dp[l][r] = max(dp[l][r], dp[l][j] + dp[j + 1][r]);
    }

SCOI2003 字符串折叠 & SCOI2007 压缩

求一个字符串的最短可嵌套压缩长度。如 AAAAAAAAAABABABCCD 最短为 9(A)3(AB)CCD

对于一个字符串,令 f i , j f_{i,j} [ i , j ] [i,j] 的最短压缩长度,有三个压缩。

  1. 原串形式,将 f i , j f_{i,j} 赋初值为 j i + 1 j-i+1
  2. 拼接形式,枚举拼接点 k k f i , j = min { f i , j , f i , k + f k + 1 , j } f_{i,j} = \min \{f_{i,j}, f_{i,k} + f_{k + 1, j} \}
  3. 嵌套形式,枚举嵌套的周期长度,若能嵌套,则转移,与重复次数的位数 + 2 + 2 即两个括号 + + 周期长度取 min。

IOI1998 Polygon

给定一个环,先删一条边,再每次选择一条边,将对应的两点合并,点权为原来两个点的点权进行边上符号的运算即为加法或乘法。求只余下一个点的最大点权。

先将长度为 n n 的环切成长度为 n × 2 n \times 2 的链。设 f i , j f_{i,j} 为区间 [ i , j ] [i,j] 的最大值。是不是枚举分界点 k k 进行区间合并?对,那就错了,因为乘法负负得正。可能两个极小的负值相乘为正值,所以用 g i , j g_{i,j} 表示最小值。

f i , j = max { f i , j , max { f i , j × f k + 1 , j , max { g i , k × g k + 1 , j , max { f i , k × g k + 1 , j , g i , k × f k + 1 , j } } } } f_{i,j} = \max \{f_{i,j}, \max \{f_{i,j} \times f_{k + 1, j}, \max \{g_{i,k} \times g_{k+1,j}, \max \{ f_{i,k} \times g_{k + 1, j },g_{i,k} \times f_{k + 1, j} \} \} \} \}

g i , j = min { g i , j , min { f i , k , f k + 1 , j , min { g i , k × g k + 1 , j , min { f i , k × g k + 1 , j , g i , k × f k + 1 , j } } } } g_{i,j} = \min \{g_{i,j}, \min \{f_{i,k}, f_{k + 1, j}, \min \{g_{i,k} \times g_{k + 1, j}, \min\{f_{i,k} \times g_{k+1,j}, g_{i,k} \times f_{k + 1, j} \} \} \} \}

HAOI2008 玩具取名

WING 四个字母,每个字母可以用 WING 中给定的任意两个字符代替,给定一个字符串,求它可以还原成WING 中哪几个字母。

如果正向还原,比较复杂,不如看作压缩。如果按字符,比较复杂,不如将字符转换为数字。有趣的是,该题不让我们求最优方案而是问有无方案,所以设 f i , j , k f_{i,j,k} [ i , j ] [i,j] 区间内的数字能否通过 k k 转换来。对于转移,枚举一个分界点 m i d mid ,检验 m i d mid 两边能不能压缩成任意可以压缩成 k k 的两个字符即可。

CQOI2007 涂色

将一个空字符串涂成给定的目标颜色字符串,每次可以涂一个区间覆盖之前的颜色,求最少涂色次数。

f i , j f_{i,j} 为将 [ i , j ] [i,j] 涂成目标颜色的最少次数。初值当 i = j i = j 时涂一次,当 i j s i = s j i \not= j \vee s_i = s_j 时,在涂 [ i , j 1 ] [i,j-1] [ i + 1 , j ] [i+1,j] 时多涂一格即可。当 i j s i s j i \not= j \vee s_i \not= s_j 时,枚举分界点 k k ,将 [ i , j ] [i,j] 分成 [ i , k ] [i,k] [ k + 1 , j ] [k+1,j] 两块来涂色即可。

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/107726474