dp 题 1

T1

Statement

你需要将 \(n(n\le10^6)\) 个数的序列 \(x\) 划分成若干连续段,设其中一段的所有数之和为 \(X\),那么这段的得分为 \(Y=aX^2+bX+c\),其中 \(a,b,c\) 已知,求划分得到的最大总得分。\(-5\le a\le-1,|b|,|c|\le10^7,1\le x_i\le100\)

Solution

\(f_i\) 表示前 \(i\) 个数组成的序列能得到的最大总得分,\(f_0=0\)\(s_i\) 表示 \(x\) 的前缀和

转移思路:枚举当前段的左端点,计算总得分 \(\max\).

\[ \begin{aligned}f_i&=\max_{j=0}^{i-1}\{f_j+a(s_i-s_j)^2+b(s_i-s_j)+c\}\\&=a\cdot s_i^2+b\cdot s_i+c+\max_{j=0}^{i-1}\{f_j+a\cdot s_j^2-b\cdot s_j-2\cdot a\cdot s_i\cdot s_j\}\end{aligned} \]

\(y=f_j+a\cdot s_j^2-b\cdot s_j\)\(k=2\cdot a\cdot s_i\)\(x=s_j\)

即若把 \(i\) 固定,\(k\) 是常量,\(y\)\(b\) 只与 \(j\) 相关;且 \(k\) 单调递减,\(x\) 单调递增.

\(f_i=a\cdot s_i^2+b\cdot s_i+c+\max_{j=0}^{i-1}\{y-kx\}\)

后面的 \(\max\{y-kx\}\) 可以通过维护上凸壳,从左往右走指针,变成总共 \(\mathcal O(n)\)

每次算完 \(f_i\),就用 \((x,y)\) 更新上凸壳

答案是 \(f_n\),时间复杂度 \(\mathcal O(n)\)

T2

Statement

\(n(n\le10^6)\) 个工厂分布在数轴上。第 \(i\) 个工厂的位置在 \(x_i(x_{i-1}<x_i)\),目前已有成品 \(p_i\) 件,在这个工厂建立仓库的费用是 \(c_i\)

对于没有建立仓库的工厂,其产品只能运往编号更大的工厂的仓库,一件产品运送一个单位距离的费用是 \(1\)。问最小的总费用(建造费用 + 运输费用)。

Solution

\(f_i\) 表示前 \(i\) 个工厂的最小费用,其中第 \(i\) 个工厂必须建仓库;则 \(f_0=0,f_1=c_1\)

\(a_i\)\(p_i\) 的前缀和,\(b_i\)\(p_ix_i\) 的前缀和

转移思路:枚举运往 \(i\) 的工厂区间的左端点,取费用的 \(\min\).

\[ \begin{aligned}f_i&=c_i+\min_{j=0}^{i-2}\left\{f_j+\sum_{k=j+1}^{i-1}p_k(x_i-x_k)\right\}\\&=c_i+\min_{j=0}^{i-2}\left\{f_j+\sum_{k=j+1}^{i-1}p_kx_i-\sum_{k=j+1}^{i-1}p_kx_k\right\}\\&=c_i+\min_{j=0}^{i-2}\{f_j+x_i(a_{i-1}-a_j)-(b_{i-1}-b_j)\}\\&=c_i+x_ia_{i-1}-b_{i-1}+\min_{j=0}^{i-2}\{f_j+b_j-x_ia_j\}\end{aligned} \]

\(y=f_j+b_j\)\(k=x_i\)\(x=a_j\),则 \(x,y\) 只与 \(j\) 相关,\(k\) 只与 \(i\) 相关;\(k\) 单调递增,\(x\) 单调不递减;

且若把 \(i\) 固定,\(\min\) 前面的式子可以直接算,\(\min\) 后面的式子变成了 \(y-kx\) 形式,

可以通过维护 \(0\sim i-2\)\((x,y)\) 组成的下凸壳,从左往右走指针的方式总共 \(\mathcal O(n)\) 地计算,

每次算完一个 \(f_i\) 就更新 \(i-1\) 对应的 \((x,y)\) 到下凸壳里面去.

答案:\(f_n\);时间复杂度:\(\mathcal O(n)\).

T3

Statement

\(N(N\le3\cdot10^5)\) 座山排成一排,第 \(i\) 座山有编号 \(P_i(1\le P_i\le N)\)、高度 \(H_i(H_i\le6\cdot10^5)\),且 \(P_i\) 互不相同,在 \(i<j\)\(P_i<P_j\) 时你可以花费 \((H_i-H_j)^2\) 的能量从第 \(i\) 座山跳到第 \(j\) 座山,同时当处于第 \(i\) 座山时,还会花费 \(A_i(|A_i|\le10^9)\) 的能量,求从第一座山到达第 \(N\) 座山的最小能量花费。

Solution

\(f_i\) 为前 \(i\) 座山,从 \(1\) 跳到 \(i\) 的最小花费,则初始时有 \(f_1=A_1\),其余 \(f_i=+\infty\)

转移思路:枚举从哪座山直接跳到第 \(i\) 座山,取花费的 \(\min\).

\[ \begin{aligned}f_i&=\min_{j\in[1..i-1]\land P_j<P_i}\left\{A_i+(H_i-H_j)^2+f_j\right\}\\&=\min_{j\in[1..i-1]\land P_j<P_i}\left\{A_i+H_i^2-2H_iH_j+H_j^2+f_j\right\}\\&=A_i+H_i^2+\min_{j\in[1..i-1]\land P_j<P_i}\left\{H_j^2+f_j-2H_iH_j\right\}\end{aligned} \]

\(y=H_j^2+f_j\)\(k=2H_i\)\(x=H_j\),则 \(x,y\) 只与 \(j\) 相关,\(k\) 只与 \(i\) 相关;

且若把 \(i\) 固定,\(\min\) 外面的式子可以直接求,\(\min\) 里面成为了 \(y-kx\),若维护出了所有满足条件的 \(j\) 对应的 \((x,y)\) 所组成的下凸壳,可以直接在下凸壳上二分 \(\mathcal O(\log n)\) 地找到答案;

而计算出当前 \(f_i\) 后还需要把它对应的 \((x,y)\) 加入下凸壳的候选点中.

问题变成了:维护 \(j<i\)\(P_j<P_i\) 的所有点组成的下凸壳,每次询问过下凸壳的每个点作斜率为 \(k\) 的直线与 \(y\) 轴的截距的最小值.

经典的扫描线问题,可以用一棵线段树或树状数组维护,每个节点对应一棵平衡树,这里以线段树为例:

  • 一个节点 \([l,r]\) 维护所有编号 \(P_k\)\([l,r]\) 内的点对应的 \((x_k,y_k)\) 组成的下凸壳
  • 每次询问的是线段树中一段前缀区间 \([1..P_i-1]\) 对应的下凸壳的每个点作出斜率为 \(k\) 的直线的 \(y\) 轴截距 \(\min\)
  • 对于涉及的 \(\mathcal O(\log n)\) 个节点,每个节点二分找到当前下凸壳的截距 \(\min\),合并时直接取 \(\min\)
  • 算完当前 \(f_i\),就将当前点加入到线段树 \(P_i\) 位置
  • 加入一个点时对于涉及的 \(\mathcal O(\log n)\) 个节点,每个点先二分找到插入位置,若能更新则对旁边的点进行删除直到再次变成凸包

无论是插入还是查询都是 \(\mathcal O(\log^2n)\) 的,总共 \(\mathcal O(n\log^2n)\)

注意,若没有满足条件的 \(j\),那么 \(f_i\) 还是 \(+\infty\);答案是 \(f(n)\).

也可以用线段树/树状数组套李超树维护

posted @ 2024-04-20 21:48  Laijinyi  阅读(3)  评论(0编辑  收藏  举报