动态规划习题分类题解 (202103) - 1. 简单线性DP
[BZOJ3398] [Usaco2009Feb] Bullcow
Description
有 (n) 只牛,其中部分牛是特殊的,特殊的牛之间至少要隔 (k) 只普通牛。求方案数。(n le 10^5)
Solution
可以提供四种解法。
DP + 前缀和
设 (f[i]) 表示放了 (i) 只牛,最后一只是特殊牛的方案数,则
前缀和优化即可。
另一种 DP
设 (f[i]) 表示放了 (i) 只牛的方案数,转移时考虑枚举上一只牛是普通还是特殊,则
注意前几位要特殊处理。
更暴力的 DP
设 (f[i][0/1]) 表示放了 (i) 只,最后一只是普通/特殊的方案数,则
显然这个方法化简一下就能直接得到第二种。
组合数学
枚举特殊牛的数量 (x),则至少需要 (k(x-1)) 只普通牛,多出来的普通牛数量为 (r=n-x-k(x-1)),而不同牛被分为 (x+1) 个段,因此我们要将 (r) 个球投入 (x+1) 个不同的盒子,球和球没有区别,盒子和盒子有区别,此时方案数为
[CF5C] Longest Regular Bracket Sequence
Description
给出一个括号序列,求出最长合法子串和它的数量。
Solution
考虑贪心地预处理出每个括号匹配的最近位置,利用栈扫一遍即可。
在处理出第 (i) 个字符的匹配位置 (j) 后,我们就可以用这一段的值去更新答案,设 (f[i]) 表示以 (i) 结尾的后缀的最大匹配长度是多少,那么很容易利用上面的信息来转移。
[CF7D] Palindrome Degree - dp
Description
一个长度为 n 字符串 s 被叫做 k 阶级回文串,当且仅当它本身是一个回文串,而且它长度为 n/2 的前缀和后缀都是 k-1 阶级回文串。任何一个字符串(包括空字符串)都至少是 0 阶级字符串。现在给定你一字符串,请你求出其所有前缀的的阶级之和。
Solution
设 (f[i]) 表示长度为 i 的前缀的阶数,如果是回文的,那么 (f[i]=f[i/2]+1),否则 (f[i]=0)
判断回文可以直接 Manacher
[CF463D] GargariandPermutations
Description
找到同时存在于 (k leq 5) 个排列中的 LCS,(n le 1000)
Solution
记录每行中每个元素的出现位置,那么本质上是一个 (k) 维偏序问题
对于 (j<i),我们暴力检查 (pos[a[j]] < pos[a[i]]) 是否对其它 (k-1) 个维度也成立,如果是就转移
[CF474D] Flowers
Description
有两种吃法:一次吃一整个蛋糕,一次吃 k 个蛋糕。当蛋糕数量为 x1 到 x2 之间时,一共能有几种不同的吃法。吃法是考虑顺序的。
Solution
设 (f[i]) 表示吃 (i) 个蛋糕的吃法有多少种
[CF710E] GenerateaString
Description
给定正整数 n,x,y,生成一个长度为 n 的字符串,有两种操作:添加或者删除一个字符代价为 x;将已有的字串翻倍代价为 y,求生成任意一个长度为 n 的字符串的最小代价。(n le 10^7)
Solution
性质:删除操作一定不会连续进行超过一次
所以我们把删除的情况手工枚举了,这样转移的拓扑结构就变成线性的了
具体地,当 i 是偶数时,转移来源为 (i-1, frac i 2)
当 i 时奇数时,转移来源为 (i-1, frac {i+1} 2)
[CF766C] MahmoudandaMessage
Description
给出一串有小写字母组成的长度为 (n le 10^3) 的字符串。每个小写字母都有对应值 (a_i),分割原串,要求对应值为 (a_i) 的字符不能出现在长度超过 (a_i) 的字串中。问共有多少种分割方式,分割后会出现的最长子串长度是多少,采用最少分割次数的方式,最少分割次数是多少?
Solution
dp,分别对三种询问进行处理,(O(n^2))
[CF1000D] YetAnotherProblemOnaSubsequence
Description
如果一个数组([a_1,a_2,a_3,...,a_n]a_1=n-1)并且(a1>0),这个数组就被叫为好数组,如果一个序列能正好分为多个好数组,ta就被叫为好序列,现在给定一个序列,求这个序列有多少好子序列,答案对(998244353)取模 (n le 5000)
Solution
设 (f[i]) 表示从 i 开始选取,有多少个符合条件的序列
转移时候需要倒着来,从后往前转移
每次枚举本次选取的是哪些元素即可
注意小于等于 0 的那些不能选,要丢掉
[CF1095E] AlmostRegularBracketSequence
Description
给定一个长度为 $ n $ 的小括号序列,求有多少个位置满足将这个位置的括号方向反过来后使得新序列是一个合法的括号序列。即在任意一个位置前缀左括号的个数不少于前缀右括号的个数,同时整个序列左右括号个数相同 $ 1 leq n leq 10^6 $
Solution
将左括号记为 (1),右括号记为 (-1),这个数字序列记为 (a[]),它的前缀和记为 (s[]),同时记录每一个后缀 (a[i..n]) 的最小前缀 (f[i])
计算 (f[]) 时,只需要倒序递推即可(类似最大子段和的处理)
如果一个位置 (i),满足所有 (i) 之前的前缀都合法,且 (s[n]-2a[i]=0),并且 (s[i-1]-a[i]+f[i+1] ge 0),则这个位置是满足条件的
[CF1120C] CompressString
Description
给定一个长度为 (n (n le 5000)) 的字符串,要求将其划分为若干段。每一段要么长度为 (1),要么是本段之前部分的子串。前者代价为 (a),后者代价为 (b),求最小总代价。
Solution
设 (f[i]) 表示划分完 (s[1..i]) 的最小总代价,则有
考虑到 (f[]) 具有单调性,因此在第二种转移中,(j) 一定要尽可能大,设 (LCS(i,j)) 表示 (s[1..i]) 与 (s[1..j]) 的最长公共后缀,则有
而 (LCS(i,j)) 可以很轻易地用 SA 求出,事实上,由于
可以在 (O(n^2)) 时间内预处理出 (LCS(i,j)),故总时间复杂度为 (O(n^2))
[CF1155D] BeautifulArray
Description
定义一个序列的美丽程度为其所有子串的和的最大值(子串可以是空的),给了你一次操作的机会,你需要选择序列的一个子串,将其中所有数乘上给定的一个常数 x,求这个序列最大的美丽程度。
Solution
设 (f[i][0/1/2]) 表示到达 i 为止的最大子段和(还没有开始用 x,正在用 x,已经不再用 x)
[CF1201D] TreasureHunting
Description
有一个 (n imes m) 的网格,方格上有 (k) 个宝藏,一个人从 ((1,1)) 出发,可以向左或者向右走,但不能向下走。给出 (q) 个列,在这些列上可以向上走,其他列不能向上走。可以重复经过同一个点。求从 ((1,1)) 出发,经过所有宝藏的最短路径长度。(n,m,k,qleq 2 imes 10^5)
Solution
设 (f[i][0/1]) 表示从 ((0,0)) 走到 (i) 行的左侧/右侧,并遍历了 (1 o i-1) 行的所有宝物的最短路径长度
[CF1353E] K-periodic Garland
Description
给定一个长度为 n 的 01 字符串,要这个字符串的每个 1 之间的距离都恰好为 k,求至少要修改几个字符。
Solution
设 (f[i]) 表示以 i 结尾((a[i]=1))的合法情况至少需要修改多少个字符
转移是从 (i-k o i),代价为 ([a[i]=0]) 加上 (a[i-k+1..i-1]) 中 1 的数量
[CF1476D] Journey
Description
有点 0...n,对于第 i 条边 (i-1,i) 告诉你该边的方向,每走一步所有边的方向都会反转,对于每个点请你求出从该点最多能走到多少个不同的点。
Solution
如果碰到两条相同的边,就会返回,所以我们预处理出每个点向右走和向左走分别能走多少步,然后枚举起始点即可