斜率优化是一种用数据结构维护(dp)的某种单调性性质从而达到优化(dp)的效果。
抽象的说,斜率优化可通过维护一个下(上)凸壳优化形如(f_i = min_{j=1}^{i-1}{ f_j + g_{i,j}})((max)同理)的转移方程。
本文只有简单推导,更充分的理解需要数形结合,请移步(OI Wiki)或其他大佬的博客。
设(f_i)为在第(i)个位置建造最后一个仓库的最小代价。
不难得出朴素的(O(n^2))转移方程
[f_i = min_{j = 0}^{i-1}{f_j+x_i imes sum_{k=j+1}^i p_k-sum_{k=j+1}^ix_k imes p_k}+c_i
]
换成前缀和的形式,令(P_i=sum_{j=1}^{i}p_i), (S_i=sum_{j=1}^ix_i imes p_i)
[f_i=min_{j=0}^{i-1}{ f_j+x_i imes(P_i-P_j)-S_i+S_j}+c_i
]
若决策(j)优于决策(k),即
[f_j+x_i imes(P_i-P_j)-S_i+S_j <f_k+x_i imes(P_i-P_k)-S_i+S_k
]
整理成斜率的形式
[frac{(f_j+S_j)-(f_k-S_k)}{S_j-S_k}<x_i
]
(ecause)(x_i)单调递增,( herefore)我们需要维护一个斜率单调递增的决策序列,即维护(f_i)函数的下凸壳。
使用单调队列维护即可,时间复杂度(O(n))。
设(t_i)为何时出发的人刚好接走它,(s_i=sum_{j=1}^it_i),(f_{i,j})前(i)个人接走前(j)只猫的最小代价。
[f_{i,j}=min_{k=0}^{j-1}{ f_{i-1,k}+t_j imes (j-k) -S_j+S_k}
]
先忽略第一维考虑第二维转移,是和上面那题类似的模式。
使用同样的套路比较决策点,然后得到斜率的形式
[frac{(f_{j}+S_j)-(f_k+S_k)}{j-k}<t_i
]
同样使用单调队列维护,转移时多枚举一维即可,时间复杂度(O(mp))
习题
例题 JSOI2011 柠檬
首先有结论:一段内首尾数字必定相同。
不难列出(dp)方程
[f_i=max_{1 leq j leq i}^{a_i=a_j}{f_{j-1}+a_i imes(s_i-s_j+1)^2}
]
其中(s_i)表示(1-i)中(a_j=a_i)的个数。
考虑决策点可得
[frac{(f_{j-1}+a_is_j^2)-(f_{k-1}+a_is_k^2)}{s_j-s_k}>2a_i(1+s_i)
]
看起来这个形式和上面两题相似,实则有些不同。
不难发现,上面两题转移越靠前越优,故用单调队列维护单调性。
此题转移越靠后越优,不难想到用单调栈维护单调性。
细节见代码,注意操作顺序。