zoukankan      html  css  js  c++  java
  • 「赛前备战」NOIp2020-提高 动态规划训练

    博主太菜,可能会炸联赛,于是恶补一下 QAQ

    题目比较基础,动态更新

    Tags

    仅包含 提高组 内容。

    • 类型:

    区间 dp背包 dp树形 dp状压 dp计数 dp数位 dp概率/期望 dp环形 dp基环树 dp

    • 优化:

    单调栈/单调队列 优化其他数据结构 优化斜率 优化倍增 优化

    Summarize

    简单总结了部分基础类型的 dp 以及一些优化。

    区间 dp

    基础状态: (f(l, r)) 表示区间 ([l, r]) ……

    基础转移模型示例:(f(l,r) = minlimits_{k}{f(l, k) + f(k+1, r)+cdots})

    基本实现:枚举区间长度,枚举左端点并计算出右端点,枚举断点。或者直接记搜。

    树形 dp

    树上动态规划。

    基础状态:(f(x, cdots)) 表示以 (x) 为根的子树……

    由于树的递归性质,基本用 Dfs 实现。

    状压 dp

    常见于元素个数较少的情况。

    基础状态:(f(S, cdots)) 表示以 (x) 为根的子树……

    集合使用二进制、位运算的思想压缩成一个整数并进行判断或转移。

    计数 dp

    常用于统计方案数。

    设计状态是重点,转移看题意。

    可能有一些组合计数的知识。

    数位 dp

    常见情况:统计值域在 ([a, b]) 中满足……条件的数的个数/数位数字和/……((a, b) 通常很大)

    一般拆成 ( ext{ans}(b) - ext{ans}(a - 1)) 计算,以记忆化搜索实现。

    搜索函数的参数一般有当前位置,前面是否有前导零,枚举时是否受当前位大小限制。但大多数题目还会有其他限制。

    数位 dp 的复杂度和位数有关。

    概率/期望 dp

    一般情况下,解决概率问题需要顺序循环,而解决期望问题使用逆序循环,如果定义的状态转移方程存在后效性问题,还需要用到转化成求解方程组的解并使用高斯消元。

    部分题目还会牵扯到状压、矩阵加速等。

    对分数取模记得逆元。

    环形 dp

    环上的 dp,一般的处理方法有断环为链然后 dp 两次或 (n) 次,或者复制一遍。

    基环树 dp

    环形 dp + 树形 dp。据说很烦,不会。

    背包 dp

    主要是挖出经典模型。

    单调栈/单调队列 优化

    一般会出现滑动最值差不多的模型,如:(f(i) = minlimits_{j<i}{f(j)+ ext{val}(i, j) }),其中 ( ext{val}(i, j)) 为一个仅存在关于 (i) 或关于 (j) 的项的多项式,不存在同时关于 (i, j) 的项。

    此时可以提出关于 (i) 的项,用单调队列维护 (f(j)) 和关于 (j) 的项,加速转移。

    斜率 优化

    上述 单调栈/单调队列 优化 的拓展。适用于 ( ext{val}(i, j)) 中含有同时关于 (i, j) 的项时的情况。

    一般可以假设来两个决策点 (a, b(a<b<i)),并设 (a) 劣于 (b)。我们可以得到一个不等式,然后变形为 (dfrac{y_a - y_b}{x_a - x_b} = ext{slope}(a, b)) 的形式。最后用单调队列维护上/下凸包即可。

    其他数据结构 优化

    一般根据转移的特征,使用合适的数据结构优化转移。

    倍增 优化

    也许会有类似与 (2^k) 这种明显的提示。

    一般把“转移 (j) 次”换成“转移 (2^k) 次”降下复杂度。

    Content

    • 「eJOI2017」Experience 树形 dp
    • 「eJOI2018」山
    • 「CSP2019-J」纪念品 背包 dp
    • 「NOIp2018-普及」摆渡车
    • 「AHOI2009」中国象棋 计数 dp
    • 「LA 4394」String painter 区间 dp
    • 「CSP2019-S」Emiya 家今天的饭
    • 「Codeforces」Coloring Brackets 区间 dp
    • 「USACO19DEC」Greedy Pie Eaters 区间 dp
    • 「NOIp2018-提高」愤怒的小鸟 状压 dp
    • 「Codeforces 372C」Watching Fireworks is Fun 单调栈/单调队列 优化
    • 「Codeforces 16E」Fish 状压 dp 概率/期望 dp
    • 「POI2014」Little Bird 单调栈/单调队列 优化
    • 「POJ 1746」Minimizing maximizer 其他数据结构 优化 - 线段树
    • 「POJ 2836」Rectangular Covering 状压 dp
    • 「POJ 1821」Fence 单调栈/单调队列 优化
    • 「HDU 3507」Print Article 斜率 优化
    • 「HNOI2008」玩具装箱 斜率 优化
    • 「HDU 2829」Lawrence 斜率 优化
    • 「THUSC 2016」成绩单 区间 dp
    • 「Codeforces 148D」Bag of mice 概率/期望 dp
    • 「Luogu P1654」OSU! 概率/期望 dp
    • 「Luogu P3413」SAC#1 - 萌数 数位 dp
    • 「SDOI2016」征途 斜率 优化
    • 「Luogu P1613」跑路 倍增 优化

    「eJOI2017」Experience

    update - 2020.7.27

    (f(x, 0), f(x, 1)) 分别表示以 (x) 为根的子树,(x) 所在链为向下(非严格)递减、递增时的答案。

    题目中要求求极差,那么结点 (x) 可能为最大值或最小值。

    以向下递减为例,我们在所以满足 (W_x ge W_y) 的所有子结点 (y) 中,将原本 (y) 的贡献用 (x) 作为新的最大值替换,并更新 (f(x, 0)) 的答案。向下递增也是同理,不过这里是作为最小值,因此符号会改变。

    在做结点 (x) 是,我们设 (p = sumlimits_{y in ext{son}(x)} max(f(y, 0), f(y, 1))),并令 (p)(f(x, 0), f(x, 1)) 的初始值。

    那么状态转移方程((leftarrow) 表示最(大)值操作):

    [f(x, 0) leftarrow maxlimits_{yin ext{son}(x), W_x ge W_y}{p - max(f(y, 0), f(y, 1)) + W_x - W_y}\ f(x, 1) leftarrow maxlimits_{yin ext{son}(x), W_x le W_y}{p - max(f(y, 0), f(y, 1)) - W_x + W_y} ]

    时间复杂度 (O(n))

    「eJOI2018」山

    update - 2020.7.27

    (f(n, k, 0), f(n, k, 1), f(n, k, 2)) 表示 ([1, n]) 中,建造了 (k) 座房子,且第 (n-1),第 (n) 个位置的状态分别为 ((0,0),(1, 0), (0, 1)) 时((0) 表示没有房子,(1) 表示有)的最小花费时间。

    状态转移方程:

    [f(n, k, 0) = min{f(n-1, k, 0), f(n-1, k, 1)} \ f(n, k, 1) = f(n-1, k, 2) + ext{get}(a_n - a_{n - 1} + 1)\ f(n, k, 2) = min{f(n-1, k-1, 0) + ext{get}(a_{n-1} - a_n + 1), f(n-1, k-1,1)+ ext{get}(min(a_{n-2}-1, a_{n-1})-a_{i}+1)}\ ext{其中 } ext{get}(x)=max(x, 0) ]

    时间复杂度 (O(n^2))

    「CSP2019-J」纪念品

    update - 2020.7.27

    直接存物品的个数显然原地升天。但仔细想一下发现,转换成统一在第 (i) 天买,然后在第 (i+1) 天卖,其实等价。因为即使对某种物品实际上并不操作,换成全卖了然后买回来也未尝不可。

    不难设计出一个比较暴力的状态:(f(i, j, k)) 表示第 (i) 天,对于前 (j) 个物品,剩余现金为 (k) 时,下一天手头上的最大现金数。转移方程显然。

    为了不空间爆炸,我们尝试优化。第一维显然可以缩掉——我们只要上一轮的最优值即可。剩下了两维看着像一个背包,于是倒序以下就只剩最后一维了。方程:

    [f(k) leftarrow max(f(k), f(k - P_{i, k})+P_{i, k+1}-P_{i, k}) ]

    时间复杂度 (O(TN imes max P))

    「NOIp2018-普及」摆渡车

    update - 2020.7.28

    (t) 数组升序排序,显然的。设 (f(i, j)) 表示第 (i) 个人等了 (j) 分钟,送走前 (i) 个人等待总时间的最小值。

    直接看 (j) 的范围貌似可以达到 (max t),但其实不然——一个人最多等 (< 2m) 分钟。

    • 相比在起点停着 (m) 分钟,啥也不管直接开一趟(尽管空车)总不会更劣,那么停车一次不超过 (T_1 < m)
    • 一个人等一辆离开的车回来的时间 (T_2 le m)

    于是一个人等待的时间 (j = T_1 + T_2 < 2m)

    那么状态的规模差不多是 (O(n m))。考虑设计转移:

    • (t_i + j ge t_{i + 1}),那么第 (i+1) 个人赶得上本趟车,则:(f(i+1, j+t_i-t_{i+1}) leftarrow f(i,j)+j+t_i-t_{i+1})
    • (t_i+j+mge t_{i+1}),那么第 (i+1) 个人可以在车回来前等车,则枚举车回来的时间 (k),转移为: (f(i+1, j+t_i+m+k-t_{i+1}) leftarrow f(i, j)+j+t_i+m+k-t_{i+1})
    • (t_i + j + m < t_{i +1}),那么第 (i+1) 个人在车回到起点后到,则枚举第 (i+1) 个人的等待时间 (k),转移为: (f(i+1, k) leftarrow f(i, j)+k)

    时间复杂度:(O(nm^2))

    「AHOI2009」中国象棋

    update - 2020.7.28

    会设状态基本就做完了。设 (f(i, j, k)) 表示考虑到第 (i) 行,有 (j) 列存在一个棋子,(k) 列有两个棋子的方案数。

    转移非常显然:

    • 不放:(f(i, j, k) leftarrow f(i-1, j, k))
    • 放在空列:
      • 放一个:(f(i, j, k) leftarrow f(i - 1, j - 1, k) imes (m - (j - 1) - k))
      • 放两个:(f(i, j, k) leftarrow f(i - 1, j - 2, k) imes C_{m - (j - 2) - k}^2)
    • 放在已经有一个的列:
      • 放一个:(f(i, j, k) leftarrow f(i-1, j+1, k-1) imes (j+1))
      • 放两个:(f(i, j, k) leftarrow f(i - 1, j + 2, k - 2) imes C_{j+2}^2)
    • 在已有一个的和空列各放一个:(f(i, j, k) leftarrow f(i - 1, j, k - 1) imes j imes (m - j - (k - 1)))

    时间复杂度 (O(nm^2))

    「LA 4394」String painter

    update - 2020.7.28

    直接算 (A, B) 串不好处理,不如先考虑空串到 (B) 的步数。设 (f(i, j)) 表示从空串到 (B[i,j]) 的最小步数。

    那么显然有:

    [f(i,j) = egin{cases} 0 & i>j\ 1 & i=j\ minlimits_{i < k le j, B_i = B_k} {f(i+1, j)+f(k + 1, j)} & i < j\ end{cases} ]

    我们令答案为 (g)(g(i)) 表示 ([1, i]) 部分的答案。那么:

    [g(i) leftarrowminlimits_{0le j < i} {g(j) + f(j + 1, i)}\ g(i) leftarrow min(g(i), g(i - 1) imes [A_i = B_i]) ]

    答案为 (g(n)),复杂度 (O(n^3))

    「CSP2019-S」Emiya 家今天的饭

    update - 2020.7.28

    分析题目性质,发现不可能有两列或以上占去一半,不合法的只可能是一列。

    那么容斥以下,答案等于 总方案数 减去 某一列不合法的方案数。

    合法的方案不难处理:(g(i, j)) 表示前 (i) 行选了 (j) 个的方案数,那么显然 (g(i, j) = g(i - 1, j) + g(i - 1, j - 1) imes sum_j a_{i,j})。可以在 (O(n^2)) 时间内解决。

    对于不合法的方案,有一个比较暴力的思路,枚举这个不合法列 (c),设 (f(i, j, k)) 为前 (i) 行,在第 (c) 列选了 (j) 个,其他列选了 (k) 个的方案数。那么有转移:

    [f(i, j, k) = f(i - 1, j, k) + f(i - 1, j - 1, k) imes a_{i, c} + (sum_j a_{i, j} - a_{i, k}) imes f(i - 1, j, k - 1) ]

    不合法的总数即为所有 (sum_{j>k} f(n, j, k)) 之和。然而这个需要 (O(n^3 m)) 的时间,只有 84 分。

    突然发现我们只需要 (j, k) 之间的差值大小,并不需要具体大小,于是又砍掉一维—— (f(i, j)) 表示当不合法列为 (c) 时,考虑到前 (i) 行,第 (c) 列的个数比其他列多 (j) 个的方案数。转移方程:

    [f(i, j) = f(i - 1, j) + f(i - 1, j - 1) imes a_{i, c} + f(i - 1, j + 1) imes (sum_j a_{i, j} - a_{i, c})。 ]

    这样时间复杂度 (O(n^2m))

    「Codeforces 149D」Coloring Brackets

    update - 2020.7.29

    显然不能直接用 (f(l, r)) 表示区间 ([l, r]) 的方案数,因为相邻位置也有影响。

    于是带上 (l, r) 的颜色:(f(l, r, x, y)) 表示区间 ([l, r]) 中,位置 (l) 颜色为 (x)(r)(y) 的方案数。颜色 (0/1/2) 分别表示无色,蓝色,红色。

    那么分三种情况讨论:

    • (l + 1 = r):边界条件,(f(l, r, 0, 1) = f(l, r, 1, 0) = f(l, r, 0, 2) = f(l, r, 2, 0) = 1)
    • 位置 (l, r) 为一组配对的括号:我们可以由区间 ([l + 1, r - 1]) 的 dp 值推出,转移显然,根据题意模拟即可。
    • 位置 (l, r) 为不配对:那么我们可以由两组配对的 dp 值推出。具体地,设位置 (l) 的右括号的位置为 (k),那么答案就由区间 ([l, k])([k + 1, r]) 得出。

    推荐使用记忆化搜索实现,复杂度 (O(|s|^2))

    「USACO19DEC」Greedy Pie Eaters

    update - 2020.7.29

    (f(i, j)) 表示区间 ([i, j]) 被全部吃完后可得的最大 (sum w_i)。那么有

    [f(i, j)=max egin{cases} maxlimits_{i le k <j} f(i, k) + f(k, j) \ maxlimits_{ile kle j} f(i, k - 1)+f(k + 1, j) +p(i, j, k) end{cases} ]

    其中 (p(i, j, k)) 表示所有满足 (i le l_xle kle r_xle j)(k)(w_k) 的最大值。求 (p) 数组可以用向外拓展的方式:

    [p(i-1, j, k) leftarrow p(i, j, k)\ p(i, j+1, k) leftarrow p(i, j, k) ]

    在计算 (p) 时应先枚举 (k)。时间复杂度 (O(n^3))

    「NOIp2018-提高」愤怒的小鸟

    update - 2020.7.29

    众所周知三点确定一条抛物线。那么设 (s(i, j)) 表示点 ((x_i, y_i), (x_j, y_j), (0, 0)) 构成的抛物线上的点集。显然可以 (O(n^3)) 预处理。

    设计状态:(f(S)) 表示覆盖点集 (S) 所需的最小抛物线数。转移:

    [f(varnothing) = 0 \ f(S cup s(i, j)) = min{f(S) + 1} \ f(S cup (x_i, y_i)) = min{f(S) + 1} ]

    这个方法是 (O(T imes 2^ncdot n^2)) 的,非常悬。

    考虑一个优化:设 (x) 为点集 (S) 中没有出现过的最小编号的点的编号,即 (x = min{x| exttt{S&(1<<(x-1))}=0, xin mathbb N^+})。那么可以限定由 (S) 拓展的转移的线必定经过第 (x) 个点。

    这相当于限定了顺序,因为原本乱序枚举与现在可以枚举到的范围其实是一样的。时间复杂度 (O(T imes 2^ncdot n))

    「Codeforces 372C」Watching Fireworks is Fun

    update - 2020.7.29

    (f(i, j)) 表示前 (i) 个烟花放完后,当前在位置 (j) 处,得到的最大快乐值。那么有:

    [f(i, j) = maxlimits_{|k-j|le d imes|t_i - t_{i-1}|}{f(i - 1, k) + b_i - |a_i - j|} ]

    显然这个 dp 是 (O(n^2m)) 的,需要优化。

    发现这个 (b) 可以提出来,那么重新定义 (f)

    [f(i, j) = minlimits_{|k-j|le d imes|t_i - t_{i-1}|}{f(i - 1, k) - |a_i - j|} ]

    答案即为 (sum b_i - min f(m, j))。又发现可以把 (|a_i-j|) 提出来,于是我们发现一个类似于 (f(i)) 一段滑动区间的最值问题,显然可以单调队列优化。发现 (k) 的范围其实有两段,于是正反各做一次, 时间复杂度 (O(nm))

    直接开数组炸空间,于是滚动数组滚掉第一维。

    「Codeforces 16E」Fish

    update - 2020.7.30

    首先要知道 (x) 个鱼中任意一对相遇的机率 (P(x) = frac{1}{x(x-1)/2})

    (n) 很小,考虑状压——(f(S)) 表示存活下来的鱼的集合为 (S) 的概率。转移:

    [f(S) = sumlimits_{i otin S,jin S} f(Scup i) imes a_{j, i} imes frac{1}{|S| imes(|S| + 1)/2} ]

    后面的 (-1) 改成了 (+1) 是因为原本的集合大小为 (|S| + 1)

    时间复杂度 (O(2^n imes n^2))

    「POI2014」Little Bird

    update - 2020.7.30

    (f(i)) 为到达第 (i) 个位置的最小消耗。那么有:

    [f(i) = minlimits_{j > 0, i - j le k} {f(j) + [d_i ge d_j]} ]

    时间复杂度 (O(qnsum k_i)),直接爆炸。

    考虑它是一个滑动最值,那么用单调队列优化这个过程。这里的比较关键字有两个:第一为 (f) 的大小,第二为 (d) 的大小。

    优化后复杂度为 (O(qn)),STL 的话可能有点卡常。

    「POJ 1746」Minimizing maximizer

    update - 2020.7.30

    有一个比较朴素的想法:(f(i, j)) 表示前 (i) 个 Sorter 中,位置 (j) 到位置 (1) 所需 Sorter 数量的最小值。那么有一个非常显然的转移:

    [f(i, j) = egin{cases} min(f(i-1, j),minlimits_{jin [s_{i-1}, t_{i-1}]} {f(i-1, k)}) & j=t_{i-1}\ f(i-1, j) & j e t_{i-1}\ end{cases} ]

    (O(nm)) 的时空复杂度根本无承受。我们发现第一位明显可以缩掉:

    [f(t_i) leftarrow min(f(t_i), minlimits_{kin[s_i, t_i]}{f(k)} + 1) ]

    然而最坏仍然是 (O(nm)) 的,于是使用线段树优化区间最值的过程,得到了 (O(mlog n)) 的优秀算法。

    「POJ 2836」Rectangular Covering

    update - 2020.7.30

    首先预处理以所有点对为对顶点的矩形的面积和覆盖点集,分别即为 (s(i, j), p(i, j))

    (f(S)) 为覆盖点集 (S) 所需的最小面积。状态转移方程:

    [f(Scup p(i, j)) = minlimits_{i e j}(f(Scup p(i, j)), f(S) + s(i, j)) ]

    注意共线的特判处理。时间复杂度 (O(2^n imes n^2))

    「POJ 1821」Fence

    update - 2020.7.31

    先将工人按位置 (S) 排序。

    (f(i, j)) 表示前 (i) 个工人,处理前 (j) 块木板,可得的 (sum P_i) 的最大值。朴素的状态转移:

    [f(i, j) = max egin{cases} f(i, j-1) \ f(i-1, j) \ maxlimits_{j - L_ile kle S_i - 1} {f(i-1, k) + P_i imes (j-k)} end{cases} ]

    显然第三个转移是 (O(n)) 的,考虑优化。

    我们把第三个拆一下:(f(i, j) = maxlimits_{j - L_ile kle S_i - 1} {f(i-1, k) - P_i imes k}+P_i imes j)

    发现中间是一个上界固定为 (S_i - 1),下界逐渐上升的区间最值问题。于是单调队列优化。

    时间复杂度 (O(nm))

    「HDU 3507」Print Article

    update - 2020.7.31

    第一道斜率优化 /cy

    若令 (f(i)) 表示前 (i) 个的最小花费。那么有一个显然的转移:

    [f(i) = minlimits_{k<i} {f(k)+(s(i) - s(k))^2+m}\ ext{其中}s(i)=sum_{j=1}^i C_i ]

    (O(n^2)) 的时耗承受不了,考虑优化。

    (k<j<i),若决策 (j) 优于 (k),那么满足不等式

    [f(j)+(s(i)-s(j))^2+m<f(k)+(s(i)-s(k))^2+m ]

    化简得

    [2s(i)< dfrac{[f(k)+s^2(k)]-[f(j)-s^2(j)]}{s(k)-s(j)} ]

    我们将 (j, k) 抽象成一个二维点 ((x_j, y_j), (x_k, y_k)),那么设 (x_t = s(t),y_t = f(t)-s^2(t)),于是有:

    [2s(i)< dfrac{y_k - y_j}{x_k - y_k} = ext{slope}(k, j) ]

    我们使用斜率优化,用单调队列维护这些点,斜率递增。

    当做到第 (i) 个时,先弹出队首不符合上述不等式的元素,再将队首直接转移至 (f(i)),然后将队尾违背斜率单调性的弹出,最后在尾部插入 (i)。弹出时须保证队中存在两个及以上的元素。

    时间复杂度 (O(n))

    「HNOI2008」玩具装箱

    update - 2020.7.31

    设前 (i) 个的最小花费为 (f(i)),则:

    [f(i) = minlimits_{j < i}{ f(j) + (i-k-1+s(i)+s(j)-L)^2 } \ ext{其中} s(i) = sum_{j=1}^i C_i ]

    为简化计算,设 (a_t = t + s(t),b_t=t+s(t)+L+1),于是:

    [f(i) = minlimits_{j<i} { f(j) + a_i^2+b_j^2-2a_i b_j} ]

    对于某个 (j),我们将原转移化为:

    [2a_i b_j + f(i) - a_i^2 = f(j) + b_j^2 ]

    (x_t = b_t, y_t = f(t) + b_t^2),那么这可以被视为一个直线的表达式,为斜率即为 (2a_i)

    斜率优化,维护一个斜率递增的单调队列即可,第一个满足斜率 ( ext{slope}(j, j+1) >2a_i)(j) 直接转移。

    时间复杂度 (O(n))

    「HDU 2829」Lawrence

    update - 2020.8.1

    显然的状态:(f(i, j)) 表示前 (i) 个站点,炸 (j) 次产生的最小值。

    显然的方程:(f(i, j) = minlimits_{k<i} { f(k, j - 1) + c(i)-c(k)-s(k) imes (s(i)-s(k)) }),其中 (s(i) = sum_{j=1}^i a_i, c(i)) 表示前 (i) 个的两两乘积和,(=c(i-1)+a(i)s(i-1))

    单次转移 (O(n)),需要优化。设 (a<b),且决策 (a) 劣于 (b),那么有 (f(a, j-1)-c(a)-s(a)s(i)+s^2(a) > f(b, j-1)-c(b)-s(b)s(i)+s^2(b)),即:

    [dfrac{[f(a, j-1)-c(a)+s^2(a)] - [f(b, j-1)-c(b)+s^2(b)]}{s(a)-s(b)} > s(i) ]

    (x_i = s(i), y_i = f(i, j-1)-c(i)+s^2(i)),那么带入上式:

    [dfrac{y_a - y_b}{x_a-x_b}= ext{slope}(a, b) > s(i) ]

    于是斜率优化。时间复杂度 (O(nm))

    「THUSC 2016」成绩单

    update - 2020.8.1

    考虑区间动规,但显然不是 (f(i, j)),因为代价与最值有关,而我们这样是无法知道的。

    正确的设法应该是,(f(i, j, l, r)) 表示区间 ([i, j]) 消去部分数,剩下数在值域 ([l, r]) 中的最小花费。

    转移?分类讨论:

    • (l = r = 0)。说明我们需要取完,分为直接取完整个区间,或先取这个区间中某段值域的数字:

    [f(i, j, l, r) = min(a+b imes (maxlimits_{ile kle j} w_i - minlimits_{ile kle j} w_i)^2, minlimits_{x, y} {f(i, j,x, y)}+a+b imes (y-x)^2) ]

    • (l e 0)(r e 0)。考虑分割这个区间。
      • 当然如果 (i=j) 的话只要判断当前值 (w_i) 是否 (in [l, r]) 即可。
      • 否则枚举断点 (k),左右两部分共有 3 中情况:左边取完,右边取完,都不取完:

    [f(i, j,l, r)leftarrow f(i, k, l, r) + f(k+1, j, l, r) \ f(i, j,l, r)leftarrow f(i, k, 0, 0) + f(k+1, j, l, r) \ f(i, j,l, r)leftarrow f(i, k, l, r) + f(k+1, j, 0, 0) ]

    可以使用记忆化搜索实现,总复杂度 (O(n^5)),但由于状态实际并没有这么多,跑不满。

    「Codeforces 148D」Bag of mice

    update - 2020.8.3

    (f(i, j)) 表示轮到公主时,袋中剩下 (i) 只白,(j) 只黑,公主胜的概率。

    首先 (f(i, j) leftarrow frac{i}{i + j}),即一下就抓到白的的情况。

    两人都抓到黑的,中途跑出一只黑的:

    [f(i, j) leftarrow f(i, j - 3) imes frac{j}{i +j} imesfrac{j-1}{i+j-1} imes frac{j-2}{i+j-2} ]

    两人都抓到黑的,中途跑出一只白的:

    [f(i, j)leftarrow f(i -1, j-2) imes frac{j}{i+j} imesfrac{j-1}{i+j-1} imes frac{i}{i+j-2} ]

    其他败的情况不计算内,复杂度 (O(w imes b))

    「Luogu P1654」OSU!

    update - 2020.8.3

    考虑这样一个等式:((x+1)^3 = x^3 + 3x^2 + 3x +1),相比 (x^3) 多出了 (3x^2 + 3x +1)

    (f(i)) 为前 (i) 个的期望分数。除此之外,还需维护一次方,二次方的期望值 ( ext{E}(x))( ext{E}(x^2))

    对于一、二次方,有:

    [ ext{E}(x) = ( ext{E}(x- 1) + 1) imes ext{prob}(i) \ ext{E}(x^2) = ( ext{E}[(x-1)^2] + 2 ext{E}(x-1) + 1) imes ext{prob}(i) ]

    对于 (f(i)) 的计算存在两种情况,当前位置取或不取:

    [f(i) = (f(i-1) + 3 ext{E}[(i-1)^2] + 3 ext{E}(i-1) + 1) imes ext{prob}(i) + f(i - 1) imes (1- ext{prob}(i)) \ = f(i-1) + (3 ext{E}[(i-1)^2] + 3 ext{E}(i-1) + 1) imes ext{prob}(i) ]

    (O(n)) 递推即可。

    「Luogu P3413」SAC#1 - 萌数

    update - 2020.8.3

    比较复杂的数位 dp。首先不能直接设 (f( ext{pos}, ext{isPa}, v_0, v_1)),而应设为 (f( ext{pos}, ext{isPa}, ex_0, v_0, ex_1, v_1))。其中从左至右分别为当前位置,之前是否已经构成回文,前二位是否有效(若为前导 0 则无效),前二位是什么数字,前一位是否有效,前一位是什么数字。多加了两维是为了防止形如 ( exttt{000041}) 这种前导 0 构成回文的实际非法的串混进来。

    考虑用记忆化搜索实现。在枚举当前位的数字时,需要多计算一个 bool 值:下一次的回文情况(下一个 ( ext{isPa}))。

    由于数位 dp 的重点根本不在方程而是实现,下面给出搜索部分的代码:

    LL f[N][2][2][D][2][D];
    
    LL solve(int pos, bool isPa, bool ex0, int val0, bool ex1, int val1, bool lim, bool zero) {
        if (!pos) return LL(isPa);
        if (!lim && !zero && (~f[pos][isPa][ex0][val0][ex1][val1]))
            return f[pos][isPa][ex0][val0][ex1][val1];
        
        LL ret = 0ll; int maxD = lim ? num[pos] - '0' : 9;
        for (int d = 0; d <= maxD; d++) {
            bool nxtPa = (val0 == d && ex0) || (val1 == d && ex1) || isPa;
            bool nxtZr = zero && (d == 0);
            bool nxtLm = lim && (d == maxD);
            (ret += solve(pos - 1, nxtPa, ex1, val1, !nxtZr, d, nxtLm, nxtZr)) %= mod;
        }
    
        if (!lim && !zero) f[pos][isPa][ex0][val0][ex1][val1] = ret;
        return ret;
    }
    

    「SDOI2016」征途

    update - 2020.8.4

    首先推式子,化简方差:(v = dfrac{1}{m}sumlimits_{i=1}^m v_i^2 - dfrac{1}{m^2}left(sumlimits_{i=1}^m v_i ight)^2),那么 (v imes m^2 = msumlimits_{i=1}^m v_i^2 - left(sumlimits_{i=1}^m v_i ight)^2)

    这个式子的第二项显然不变,着重考虑第一项中的平方和部分。

    (f(t, i)) 表示走了 (t) 段到位置 (i) 的最小平方和。那么朴素的转移:

    [f(t, i) = minlimits_{j<i} {f(t-1, j) + [s(i) - s(j)]^2}\ s ext{为前缀和。} ]

    这个 (O(n)) 一次的转移显然可以斜率优化。

    具体的,我们设 (a < b)(a) 劣于 (b),那么:

    [f(t-1, a) + [s(i) - s(a)]^2 > f(t-1, b) + [s(i) - s(b)]^2 \ downarrow \ dfrac{[f(t-1, a) + s^2(a)] - [f(t-1, a) + s^2(b)]}{s(a) - s(b)} > 2s(i)\ downarrow \ ext{slope}(a, b) > 2s(i) ]

    然后用单调队列维护一个斜率递增的下凸包即可。复杂度 (O(nm))

    「Luogu P1613」跑路

    update - 2020.8.4

    这是一个最短路问题,但真正的图并不是原图。我们设 (f(u, v)) 为结点 (u, v) 的联通情况,现在需要处理出这个图。

    看到 (2^k) 就很显然是倍增。设 (g(u, v, t)) 为是否存在连接 (u, v) 长度为 (2^t) 的路径。那么可以用 dp 的方法处理出来:

    [g(i, j, t) = operatornameorlimits_{kin ext{V}} { g(i, k, t-1) and g(k, j, t-1) } ]

    对于 (f(i, j)) 的值,若存在一个 (tin[0, log_2( ext{maxlongint})]),使得 (g(i, j, k)= exttt{true}),那么 (f(i, j) = 1),反之则为 (infty)

    最后在 (f) 上跑 Floyd 即可。时间复杂度 (O(n^3 log m))

    后记

  • 相关阅读:
    什么是电信BOSS系统?
    得到windows系统图标的解决方案
    FusionChart实现金字塔分布图
    OCP-1Z0-051-V9.02-91题
    FusionChart用XML和JSON两种格式提供数据源
    OCP-1Z0-051-V9.02-156题
    OCP-1Z0-051-V9.02-155题
    OCP-1Z0-051-V9.02-154题
    OCP-1Z0-051-V9.02-153题
    OCP-1Z0-051-V9.02-151题
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/13385430.html
Copyright © 2011-2022 走看看