斜率优化笔记

updated 2022.3.12:
把一堆代码块删了,换成了测评记录 顺眼多了(


\(f_i\) 是前 \(i\) 个都装好的最小花费.

\[f_i=min_{j=1}^{i-1}\{ f[j]+(F(i,j)-1-L)^2\} \]

其中

\[F(i,j)=\sum_{k=j+1}^{i}C_k+(i-j) \]

\[g(x)=\sum_{i=1}^xC_i+x \]

\[F(i,j)=g(i)-g(j) \]

为了简便让

\[L \leftarrow L+1 \]

\[\therefore f_i=min_{j=1}^{i-1}\{f_j+(g(j)+L)^2-2g(i)g(j)\}+g^2(i)-2g(i)L \]

如果 \(j\) 优于 \(k\)

\[f_j+(g(j)+L)^2-2g(i)g(j) \le f_k+(g(k)+L)^2-2g(i)g(k) \]

\[\therefore [f_j+(g(j)+L)^2]-[f_k+(g(k)+L)^2] \le 2g(i)(g(j)-g(k)) \]

\[def\;H_j=f_j+(g(j)+L)^2\,, \]

\[\therefore \frac{H_j-H_k}{g(j)-g(k)} \le 2g(i) \]

左边这一坨就是两个决策点的slope
S单增,H单增
用蝉蜩队列维护
每次把队头逼近至与下一点斜率 \(\gt 2g(i)\) 然后用该点更新
(注意是大于不是小于,画个图比较清楚)
因为每次相当于把平面旋转,使得原来斜率是 \(2g(i)\) 的某条直线变成 \(x\) 轴,然后找到 \(y\) 坐标最小的点更新(最低点即是该情况下直线与凸壳的切点)

然后就是slope不要打成 \(\large\frac{g(j)-g(k)}{H_j-H_k}\) 了( 人类智慧巅峰

record


一开始的心路历程(放在paste上的):

\[f_i=min_{j=1}^{i-1}\{f_j-(S_i-S_j)+(i-j)t_i\} \]

\[S_x=\sum_{i=1}^xt_x \]

如果 \(j\,Ge\,k\)

\[f_j-S_i+S_j+(i-j)t_i \le f_k-S_i+S_k+(i-k)t_i \]

\[(f_j+S_j)-(f_k+S_k) \le t_i(j-k) \]

\[H_x=f_x+S_x \]

\[\therefore \frac{H_j-H_k}{j-k} \le t_i \]

t排序之后是单增
分子函数就是 \(f(x)=x\) 单增,分母关于 \(x\) 单增
吔,怎么突然又行了(
焯,dp柿子错了
我直接升天(

\[f_i=min_{j=1}^{i-1}\{f_j-(S_i-S_j)+(i-j)T_{i,j}\} \]

\[S_x=\sum_{i=1}^xt_x \]

\[T_{i,j}=max\{t_i,t_j+m\} \]

艹……

然后糊上去 \(O(n^2)\) ,发现WA了(
就算了(

record


拿到疯狂直接想一维dp,然后迷惑了很久(
然后发现它是二维dp改过来的

\(f[i][j]\) 表示共分了 \(i\) 组,这一组的最后一个是 \(j\) 的最小花费
然后

\[f[i][j]=min_{k=1}^{j-1}\{f[i-1][k]+(\sum_{l=1}^{j}t_l+i \times S)\sum_{l=k+1}^{j}f_l\} \]

然后它是 \(n^3\) 的,完全不行

然后看到说可以进行费用提前计算
也就是说,因为每分出一组就会对后面每一组产生 \(S\) 的时间上的贡献,所以把这部分提前拉到 \(f_{i,j}\) 来算

\[f_i=min_{j=1}^{i-1}\{f_j+T_i(F_i-F_j)+S(F_n-F_i)\} \]

注意要在 \(f_0\) 提前算第一次启动造成的贡献
斜优柿子是 \(\large\frac{f_j-f_k}{F_j-F_k} \le T_i\)

up:
如果不预处理 \(f_0\) ,还可以这样:

\[f_i=min_{j=1}^{i-1}\{f_j+T_i(F_i-F_j)+S(F_n-F_j)\} \]

这时斜优柿子变成 \(\large\frac{f_j-f_k}{F_j-F_k} \le T_i+S\)

record on LG

record on LOJ


上面的加强版
\(F_i\) 单调不减, \(T_i\) 不单调
对于第一条,这说明还是可以用单调队列维护凸壳,但是需要判断两个点的横坐标相同
对于第二条,根据斜优的三个套路,需要在队列里二分查找最优决策点

然后套上强无敌的D5eM二分就行了 (×)
然后经过无数次玄学尝试设置好了初始区间就行了 (√)

啊?什么?你问我为什么二分要这样写?
我也不知道啊,但是这样能过

就地总结一下fym二分的注意点

    1. \(r\) 的初值一定要设置成右端点下一位,即 \(r=right+1\) ,因为判断的地方实际上作用是按照精度 \(1\) 判断 \(l=r\) ,如果想要能够查找到右端点就需要把上界设置成下一位(最后返回的是 \(l\) 指针)
    1. \(mid\) 进行 \(check\) 的过程中,始终记住右指针代表的是查找右端点的下一位,也就是说普通二分检查的是 \(mid\)\(mid+1\) 来判断 \(mid\) 合法性,而fym二分应该检查 \(mid-1\)\(mid\) .

另外还有一些玄学的地方,比如在运输计划中的fym二分(
这个就看脸了(大雾
这种时候就改成这样罢:

ri l=lef,r=rig,mid;
while(l^r) mid=l+r>>1,(chk(mid)?r=mid:l=mid+1);

orz

record on LG

record on LOJ


斜率优化是一款教训
教训是一款状态不一定只有一维
以及可以滚动数组防止空间被橄榄
(我竟然不是第一个搞这种骚操作的)
要说的都在注释里,这里不写了

record


昨天看这个题,感觉无从下手,非常恐怖
然后下午回来一看基本就行了

因为只能向山下运送,就不用考虑自己前面建了的仓库会对自己产生影响,因为它们夹出来的这一段只能运到自己这里
而结合到题意,最后一个产品数量不为 \(0\) 的工厂必定会被建仓库
所以就曲线救国设计状态:
\(f_i\) 表示在 \(i\) 工厂建仓库的最小费用
所以

\[f_i=min_{j=1}^{i-1}\{f_j+x_i(P_i-P_j)-(S_i-S_j)+c_i\} \]

其中

\[S_i=\sum_{j=1}^{i}x_jp_j \]

\[P_i=\sum_{j=1}^{i}p_j \]

然后搞斜优上套路就好了
注意要判断末尾的工厂是否产品数为 \(0\) ,因为空工厂可以当作空气(

record


有了上一题的铺垫很容易想了.
题目稍有不同,厂子总数只有两个,并且可以建在路上
但是正经人谁建在路上啊,很明显建在某棵树上比建在路上优
所以就和上一题完全一致了

明显这题需要的是两个维度,设 \(f_{i,j}\) 表示建了 \(j\) 个厂,第 \(j\) 个在 \(i\) 树上的最小费用
然后定睛一看, \(f_{i,0}=0\) ,砍掉一层
然后定睛一看, \(f_{i,1}\) 是直接计算不用dp
然后就砍成了一层
然后定睛一看,转移不会用到同层的值
然后就砍成了 \(0\) 层,连个 \(f\) 数组都不需要了.

record

posted @ 2022-03-12 16:17  Neutral1sed  阅读(42)  评论(0)    收藏  举报